出。
虽然两个步骤都不能省略,但只要实现其中的一个就能消除大多数的
SQL 注入风险。如果
你只是过滤输入而没有转义输出,你很可能会遇到数据库错误(合法的数据也可能影响
SQL 查询的正确格式),但这也不可靠,合法的数据还可能改变 SQL 语句的行为。另一方
面,如果你转义了输出,而没有过滤输入,就能保证数据不会影响
SQL 语句的格式,同时
也防止了多种常见
SQL 注入攻击的方法。
当然,还是要坚持同时使用这两个步骤。过滤输入的方式完全取决于输入数据的类型(见第
一章的示例),但转义用于向数据库发送的输出数据只要使用同一个函数即可。对于
MySQL 用户,可以使用函数 mysql_real_escape_string( ):
代码如下
:
<?php
$clean
=
array
();
$mysql
=
array
();
$clean
['last_name'] = "O'Reilly";
$mysql
['last_name'] = mysql_real_escape_string(
$clean
['last_name']);
$sql
= "INSERT
INTO user (last_name)
VALUES ('{$mysql['last_name']}')";
?>
尽量使用为你的数据库设计的转义函数。如果没有,使用函数
addslashes
()是最终的比较好
的方法。
当所有用于建立一个
SQL 语句的数据被正确过滤和转义时,实际上也就避免了 SQL 注入
的风险。如果你正在使用支持参数化查询语句和占位符的数据库操作类(如
PEAR::DB,
PDO 等),你就会多得到一层保护。见下面的使用 PEAR::DB 的例子:
代码如下
:
<?php
$sql
= 'INSERT
INTO user (last_name)
VALUES (?)';
$dbh
->query(
$sql
,
array
(
$clean
['last_name']));
?>
由于在上例中数据不能直接影响查询语句的格式,
SQL 注入的风险就降低了。PEAR::DB 会
自动根据你的数据库的要求进行转义,所以你只需要过滤输出即可。
如果你正在使用参数化查询语句,输入的内容就只会作为数据来处理。这样就没有必要进行
转义了,尽管你可能认为这是必要的一步(如果你希望坚持转义输出习惯的话)。实际上,
这时是否转义基本上不会产生影响,因为这时没有特殊字符需要转换。在防止
SQL 注入这
一点上,参数化查询语句为你的程序提供了强大的保护。
注:关于
SQL 注入,不得不说的是现在大多虚拟主机都会把 magic_quotes_gpc 选项打开,
在这种情况下所有的客户端
GET 和 POST 的数据都会自动进行
addslashes
处理,所以此时
对字符串值的
SQL 注入是不可行的,但要防止对数字值的 SQL 注入,如用
intval
()等函数