前言
PHP对字符串处理方面支持度很高,有很多字符串处理函数。面对复杂的WEB环境和各种网络攻击,需要保证我们在处理字符串时要考虑到安全性的方面。
正文
作为一种Web脚本语言,有两种很常见的需求:
- 处理用户输入;
- 将结果输出到WEB页面上进行显示;
对(1)处理不当,可能会产生SQL注入、XSS攻击等,对(2)处理不当,也会造成站点被XSS攻击,格式错乱等错误。
从安全角度出发,对于上述二者的处理,要遵循以下原则:
永远不要信任用户输入,在输出到页面前一定要进行转义。
处理用户输入
防止SQL注入
当用户的输入需要存入数据库时,我们要注意防止SQL注入。在输入时,可以通过mysql_real_escape_string
函数来进行对输入字符串进行转义。
不过这个函数在PHP5.5的时候已经弃用了。
使用高于5.5的PHP进行数据库操作时,强烈推荐使用PDO方式连接数据库。
验证用户输入合法性
当存在用户输入时,我们需要判断用户输入的合法性,如是否是合法邮箱、URL、IP地址等。这个功能通常是通过正则匹配来完成的,但是正则匹配比较难写,并且容易出错,所以推荐使用PHP的Filter扩展。
这个扩展定义了常见输入格式的过滤器,通过调用filter_var
函数可以轻松地实现对于用户输入的过滤。
示例代码:
var_dump(filter_var('bob@example.com', FILTER_VALIDATE_EMAIL));
var_dump(filter_var('http://example.com', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED));
执行结果:
string(15) "bob@example.com"
bool(false)
说明 bob@example.com 是一个合法的Email,而 http://example.com 不是一个带文件路径的URL。
剔除HTML标记
在一些允许用户会更新的站点,我们需要剔除用户输入的HTML标签来避免一些恶意用户进行的非法操作。
这时可以采用strip_tags
函数来实现这个功能,它会移除以<
开头和以>
结尾的内容,其他内容保持不变。
示例代码:
$string = 'This is <b>bold</b> and this is <i>italic</i>. This is a <a href="xxxx">link</a>';
echo $string;
echo '<br>';
echo strip_tags($string);
页面展示如下:
可见,直接输出是带有HTML标签的,而通过strip_tags
处理之后,没有了HTML标签,直接输出了一个字符串。
另外,strip_tags
的第二个参数可以设置忽略的标签,如不想剔除<b>
,可以将它作为第二个参数。
$string = 'This is <b>bold</b> and this is <i>italic</i>. This is a <a href="xxxx">link</a>';
echo strip_tags($string, '<b>');
页面展示如下:
可见,除了函数忽略了<b>
标签。
注:如果
<
没有闭合,那么strip_tags
函数会删除从当前位置到字符串尾部的所有文本。
输出内容到页面
在输出内容到页面时,我们要考虑到某些字符串可能会有特殊的含义,如果处理不当,最好的情况是输出的字符串难以理解;最差的情况,输出的字符串造成了某些安全问题。
所以,在输出时,要注意以下这几个问题:
- 输出是否是URL(
<a>
标签内的href值)? - 输出是否是HTML元素?
- 是否要保留格式?
构造URL
在构造URL时,如果这个URL中包含着汉字、空格、&、<、>等特殊符号时,可能的输出和我们想到不太一样,这时需要进行URL转义。
PHP中有两个函数,可以用于URL转义,分别是rawurlencode
和urlencode
,它们的区别只有一点:
对于空格,rawurlencode
会转义为%20
,urlencode
会转义为+
。
在输出URL时,推荐选用rawurlencode
。
输出为HTML元素
如果要将输出直接显示在HTML页面上,在输出前最好用htmlentities
函数将内容进行转换,转成HTML实体,这样可以在一定程度上防范XSS攻击。
例如下面的代码:
$output = '<script>alert("hello")</script>';
echo $output;
当打开这个页面时,就会执行这个JS语句,弹出一个提示框,进行了XSS攻击,效果如下:
但是如果我们将它通过htmlentities
进行转义,就会直接输出这句话。
$output = '<script>alert("hello")</script>';
echo htmlentities($output);
不会产生XSS攻击,执行结果如下:
保留换行格式
有时候,我们希望页面上的显示内容能和输出字符串一样,也就是能保留换行,这时我们可以用nl2br
函数。
示例代码:
$output = '1st line
2nd line
3rd line';
echo $output;
输出如下:
1st line 2nd line 3rd line
实例代码:
$output = '1st line
2nd line
3rd line';
echo nl2br($output);
输出如下:
1st line
2nd line
3rd line
指定字符数后换行输出
这个需求在我们需要输出到一个指定宽度的区域内很常见,例如div的宽度只有10字符,我们希望输出的字符串也能每10个字符进行一次换行。
这时可以使用wordwrap
来实现,它的作用是每隔n个字符插入指定字符,当指定字符为<br>
时,就实现了每隔n个字符进行换行。
示例代码:
$output = 'this is a very-long-long-long word.';
echo wordwrap($output, 10, '<br>');
此时输出为:
this is a
very-long-long-long
word.
我们发现其实并没有严格按照每10个字符进行分割,而是保留了单词的完整性。如果想严格按照10个字符进行切割,将第4个参数设置为true。
$output = 'this is a very-long-long-long word';
echo wordwrap($output, 10, '<br>', true);
此时输出为:
this is a
very-long-
long-long
word
总结
其实这篇博客就是介绍了几个函数的使用:
- URL转义:rawurlencode/urlencode;
- HTML转义:htmlentities
- 保留换行:nl2br
- 指定字符数换行:wordwrap
- 剔除HTML标签:strip_tags
- 验证用户输入合法性:Filter扩展