background image

出。
虽然两个步骤都不能省略,但只要实现其中的一个就能消除大多数的

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

()等函数