PDO防止sql注入的原理
首先,PDO可以被认作是一种通过编译SQL语句模板来运行sql语句的机制。
预处理语句可以带来两大好处:
1.查询只需要被解析(或编译)一次,但可以执行多次通过相同或不同的参数。当查询处理好后,数据库将分析,编译和优化它的计划来执行查询。对于复杂的查询这个过程可能需要足够的时间,这将显著地使得应用程序变慢,如果有必要,可以多次使用不同的参数 重复相同的查询。通过使用处理好的语句的应用程序避免重复 【分析/编译/优化】 周期。这意味着,预处理语句使用更少的资源,而且运行得更快。
2.绑定的参数不需要使用引号;该驱动程序会自动处理。如果应用程序使用预处理语句,开发人员可以确保不会发生SQL注入(但是,如果查询的其他部分使用了未转义的输入,SQL注入仍然是可能的)。
预处理语句非常有用,PDO可以使用一种本地模拟的办法来为没有预处理功能的数据库系统提供这个功能。这保证了一个应用可以使用统一的访问方式来访问数据库。
使用PDO可以带来两个很好的效果,预编译带来查询速度的提升,变量的绑定可以预防 sql injection,其实PDO的预防sql注入的机制也是类似于使用 mysql_real_escape_string 进行转义。
PDO 有两种转义的机制:
(1)第一种是本地转义,这种转义的方式是使用单字节字符集(PHP < 5.3.6)来转义的( 单字节与多字节 ),来对输入进行转义,但是这种转义方式有一些 隐患 。隐患主要是:在PHP版本小于5.3.6的时候,本地转义只能转换单字节的字符集,大于 5.3.6 的版本会根据 PDO 连接中指定的 charset 来转义。PHP官方手册这里有 说明 :
不同的版本的PDO 在本地转义的行为上是有区别的。
(2)第二种方式是PDO,首先将 sql 语句模板发送给Mysql Server,随后将绑定的字符变量再发送给Mysql server,这里的转义是在Mysql Server做的,它是根据你在连接PDO的时候,在charset里指定的编码格式来转换的。这样的转义方式更健全,同时还可以在又多次重复查询的业务场景下,通过复用模板,来提高程序的性能。如果要设置Mysql Server 来转义的话,就要首先执行:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
绑定的变量:
如果不执行 $pdo ->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); PDO 只是会将插入的参数使用本地转义之后和SQL模板拼装起来,然后一起发送给Mysql Server。这实际上与使用mysql_real_escape_string()过滤,然后拼装这种做法并没有什么不同。
要对数据库的安全做出更加全面的考量,以下两种方式任选其一:
A. 通过添加(php 5.3.6以前版本):$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
B. 升级到php 5.3.6 (不用设置PDO::ATTR_EMULATE_PREPARES也可以)
为了程序移植性和统一安全性,建议使用$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false)方法