开发过程中需要对用户的输入进行转义,不论是安全地显示用户在表单提交中输入的数据,还是在处理 sql 语句时,进行安全地转义可以有效避免跨站脚本攻击(XSS)和 SQL 注入。

1. 使用 htmlentities() 和 htmlspecialchars()

在处理用户提交的表单数据时,先将用户的输入进行转义,再显示在页面上。

可以使用 htmlentities() 和 htmlspecialchars() 函数将特殊字符转换成 HTML 实体(例如把 < 转换成 &lt;)。最基本的是 htmlspecialchars(),可以转义 4 个字符: < > " 和 &(可以根据可选的参数决定转义的字符)。对于更复杂的编码,需要使用 htmlentities(),可以对任何 HTML 实体进行转换。

例:

<?php

$html = "<script>alert('<a href=\"http://baidu.com?user=dee&browser=chrome\">baidu.com</a>');</script>";

echo $html,PHP_EOL; //会弹出alert提示框
//浏览器右键查看源代码
//<script>alert('<a href="http://baidu.com?user=dee&browser=chrome">baidu.com</a>');</script>

echo htmlentities($html),PHP_EOL; 
//浏览器右键查看源代码
//<script>alert('<a href="http://baidu.com?user=dee&browser=chrome">baidu.com</a>');</script>

echo htmlspecialchars($html),PHP_EOL;								//转义双引号 < > &
//浏览器右键查看源代码
//<script>alert('<a href="http://baidu.com?user=dee&browser=chrome">baidu.com</a>');</script>

echo htmlspecialchars($html, ENT_QUOTES),PHP_EOL;		//转义双引号和单引号 < > &
//浏览器右键查看源代码
//<script>alert('<a href="http://baidu.com?user=dee&browser=chrome">baidu.com</a>');</script>

echo htmlspecialchars($html, ENT_NOQUOTES),PHP_EOL;	//非单引号和双引号
//浏览器右键查看源代码
//<script>alert('<a href="http://baidu.com?user=dee&browser=chrome">baidu.com</a>');</script>

  

2. 防止注入攻击,建议使用 PDO 的参数绑定

使用参数绑定时,PDO 会对各个参数加引号和进行转义

例:

<?php

$user = 'root';
$pwd = '';
try{
	$mysql = new PDO('mysql:host=127.0.0.1;port=3306;dbname=test', $user, $pwd);
} catch(Exception $e) {
	print 'Database problem:'.$e->getMessage();
	die;
}

$st = $mysql->prepare('INSERT INTO family (id,name,is_naive) VALUES (?,?,?)');
$st->execute(array('','Lee',0));

 

如果不使用参数绑定,则需要自行转义:手动加引号,并且将 SQL 的通配符 _ 和 % 也进行 \ 转义

<?php

$user = 'root';
$pwd = '';

try{
	$mysql = new PDO('mysql:host=127.0.0.1;port=3306;dbname=test', $user, $pwd);
} catch(Exception $e) {
	print 'Database problem:'.$e->getMessage();
	die;
}

$str = "dee's_ books%";

/*使用PDO::quote()自行转义*/
echo $str,"<br />"; 
// dee's_ books%

echo $safe = $mysql->quote($str),"<br />"; 
// 'dee\'s_ books%'

$safe = strtr($safe, array('_'=>'\_', '%'=>'\%'));
echo $safe;
// 'dee\'s\_ books\%'

$st = $mysql->query("SELECT * FROM files WHERE contents LIKE $safe");

 

注意:不论是自定义转义还是使用 PDO::quote() 转义之前,都要判断服务器是否开启了魔法引号(magic_quotes_gpc 在 PHP 5.4.0 中被移除),如果开启了 magic_quotes_gpc,则关闭或者使用 addlashes() 处理传入的参数(尽量关闭魔法引号):

/* magic_quotes_sybase 为 0 时,addlashes() 对 ' " \ 进行 \ 转义 */
/* magic_quotes_sybase 为 1 时,addlashes() 对 ' 进行 " 转义 */
if(get_magic_quotes_gpc() && ! ini_get('magic_quotes_sybase')) {
	$str = stripslashes($str);
} 

$st = $mysql->prepare('UPDATE files SET contents = ? WHERE id = 1');
$st->execute(array($str));