PDO防注入原理分析以及使用PDO的注意事项总结
本文详细讲述了PDO防注入原理分析以及使用PDO的注意事项,分享给大家供大家参考。具体分析如下:
我们都知道,只要合理正确使用PDO,可以基本上防止结构化查询语言注入的产生,本文主要回答以下两个问题:为什么要使用PDO而不是mysql_connect?为何PDO能防注入?使用PDO防注入的时候应该特别注意什么?一、为何要优先使用PDO?
服务器端编程语言(专业超文本预处理器的缩写)手册上说得很清楚:准备好的语句和存储过程任何较成熟的数据库都支持准备好的语句的概念。它们是什么?它们可以被认为是应用程序想要运行的结构化查询语言的一种编译模板,可以使用可变参数进行定制。事先准备好的声明有两大好处:
查询只需要解析(或准备)一次,但是可以使用相同或不同的参数执行多次。当准备好查询时,数据库将分析、编译和优化其执行查询的计划。对于复杂的查询,这个过程可能会占用足够的时间,如果需要用不同的参数多次重复相同的查询,这将显著降低应用程序的速度。通过使用准备好的语句,应用程序避免了重复分析/编译/优化周期。这意味着准备好的语句使用更少的资源,因此运行得更快。
准备好的语句的参数不需要引用;驱动程序会自动处理这个问题。如果应用程序专门使用准备好的语句,开发人员可以确定不会出现结构化查询语言注入(但是,如果查询的其他部分是用非转义输入构建的,SQL注入仍然是可能的)。即使用PDO的准备方式,主要是提高相同结构化查询语言模板查询性能、阻止结构化查询语言注入同时,PHP手册中给出了警告信息在PHP 5.3.6之前,这个元素被默默忽略了。使用PDO :3360 MySQL _ ATTR _ INIT _ COMMAND驱动程序选项可以部分复制相同的行为,如下例所示。警告下面示例中的方法只能用于与美国信息交换标准代码共享相同的低位七位表示的字符集,如国际标准化组织8859-1和UTF .使用具有不同表示形式的字符集(如UTF-16或Big5)的用户必须使用PHP 5.3.6和更高版本中提供的字符集选项。意思是说,在PHP 5.3.6及以前版本中,并不支持在数据平滑网络(雷达)中的字符集定义,而应该使用ATTR _初始化_命令设置初始SQL,即我们常用的设置名称gbk指令。我看到一些程序,还在尝试使用添加斜线达到防注入的目的,殊不知这样其实问题更多,详情请看//www .JB 51。net/article/49205。html文件的后缀还有一些做法:在执行数据库查询前,将结构化查询语言中的选择,联合,之类的关键词清理掉。这种做法显然是非常错误的处理方式,如果提交的正文中确实包含学生会,替换后将篡改本来的内容,滥杀无辜,不可取。二、为何PDO能防结构化查询语言注入?请先看以下服务器端编程语言(专业超文本预处理器的缩写)代码:复制代码代码如下:php$pdo=新PDO(' MySQL :主机=192。168 .0 .1;dbname=testcharset=utf8 ',' root ');$ ST=$ PDO-准备('从信息中选择*其中id=?和名称=?");$ id=21 $ name=' Zhang San $ ST-BindParam(1,$ id);$st-bindParam(2,$ name);$ ST-execute();$ ST-Fetchall();环境如下:PHP 5.4.7Mysql协议版本10MySQL服务器5.5.27为了彻底搞清楚服务器端编程语言(专业超文本预处理器的缩写)与关系型数据库服务器通讯的细节,我特别使用了wireshark抓包进行研究之,安装wireshak之后,我们设置过滤条件为tcp.port==3306,如下图
这样只显示与mysql 3306端口的通信数据,避免不必要的干扰。特别是wireshak基于wincap驱动,不支持监听本地环回接口(也就是用php连接本地mysql的方法不能监听),所以请连接其他机器的MySQL(桥接网络的虚拟机也可以使用)进行测试。然后我们运行我们的PHP程序,监听结果如下。我们发现PHP只是将SQL直接发送到MySQL服务器:
实际上,这与我们通常使用mysql_real_escape_string来转义字符串,然后将它们拼接成sql语句(仅由PDO本地驱动程序转义)没有什么不同。显然,SQL注入可能仍会发生这种情况。也就是说,在php中本地调用pdo prepare中的mysql_real_escape_string来操作查询,使用的是本地单字节字符集,但是当我们传递多字节编码变量时,仍然可能会造成sql注入漏洞(这也是php 5.3.6之前的问题之一,解释了为什么在使用pdo时建议升级到php 5.3.6并在DSN string中指定charset。对于php 5.3.6之前的版本,以下代码仍可能导致SQL注入问题:复制的代码如下: $ PDO-query(' SET NAMES GBK ');$var=chr(0xbf)。chr(0x27)。OR 1=1/*;$ query=' SELECT * FROM info WHERE name=?';$ stmt=$ PDO-prepare($ query);$ stmt-execute(array($ var));原因与上述分析一致。正确的转义应该是给mysql服务器分配一个字符集,然后给MySQL服务器发送变量,根据字符进行转义。那么,如何才能禁止PHP在本地逃逸,让MySQL Server逃逸呢?PDO有一个名为PDO :3360 attr _ simulate _ prepares的参数,它指示是否使用PHP在本地模拟prepare。此参数的默认值未知。而且根据我们刚才抓取的包的分析结果,php 5.3.6默认还是使用局部变量转换,然后拼接成SQL并发送给MySQL Server。我们将该值设置为false以尝试这种效果,如以下代码所示:
复制代码代码如下:php$pdo=新PDO(' MySQL : host=192 . 168 . 0 . 1;dbname=test',' root ');$ PDO-setAttribute(PDO : attr _ EMULATE _ PREPARES,false);//这是我们刚刚添加的$ ST=$ PDO-准备('从id=?和名称=?”);$ id=21$ name=' zhangsan$st-bindParam(1,$ id);$st-bindParam(2,$ name);$ ST-execute();$ ST-Fetchall();运行程序,使用wireshark捕获并分析包,结果如下:
看到了吗?这就是神奇之处。可以看到,PHP向MySQL发送了两次SQL模板和变量,MySQL完成了变量的转义处理。由于变量和SQL模板发送了两次,不存在SQL注入问题,但是需要在DSN中指定charset属性,例如复制代码如下: $ PDO=new PDO(' MySQL 3360 host=localhost;dbname=testcharset=utf8 ',' root ');这样,SQL注入问题就可以从根本上消除。如果对此不太清楚,可以发邮件给[emailprotected]一起讨论。三、使用PDO的注意事项
了解以上几点后,我们可以总结出利用PDO消灭SQL注入的几个注意事项:
1.php升级到5.3.6,强烈建议在生产环境中升级到php 5.3.9 php 5.4,php 5.3.8存在致命的哈希冲突漏洞。2.如果使用php 5.3.6,请在PDO的DSN中指定字符集属性
3.如果使用了php 5.3.6及以前的版本,并且PDO :3360 attr _ simulate _ prepares参数设置为false(即mysql处理变量),那么PHP 5.3.6及以上版本已经处理了这个问题,无论是使用本地模拟prepare还是调用MySQL服务器prepare。在DSN中指定字符集无效,必须执行集名字符集。4.如果使用PHP 5.3.6及以前的版本,由于默认情况下Yii框架没有设置attr _ emulate _ prepare的值,请在数据库配置文件中将emulatePrepare的值指定为false。那么,有一个问题,如果在DSN中指定了字符集,还需要执行集名字符集吗?
是的,我不能。字符集实际上有两个功能:
A.告诉mysql服务器客户端(PHP程序)向它提交了什么代码。告诉mysql服务器客户端需要什么代码。
也就是说,如果数据表使用gbk字符集,PHP程序使用UTF-8编码,我们可以在执行查询之前运行set names utf8,告诉mysql服务器正确编码,而不需要在程序中进行编码和转换。这样,我们以utf-8编码向mysql服务器提交查询,结果将是utf-8编码。把转换编码问题保存在程序中,不要有任何疑问,它不会产生乱码。那么在DSN中指定字符集的目的是什么呢?只需告诉PDO,本地驱动程序在转义时应该使用指定的字符集(而不是mysql服务器通信字符集),设置mysql服务器通信字符集,并使用set names charset指令。我真的不明白为什么一些新项目用传统的mysql_XXX函数库代替PDO。如果正确使用PDO,就可以从根本上消灭SQL注入。我强烈建议各公司技术负责人和一线技术R&D人员注意这个问题,尽可能利用PDO加快工程进度和安全质量。不要试图编写自己的SQL注入过滤器库(这很繁琐,容易产生未知的漏洞)。
希望这篇文章对大家的PHP编程有所帮助。
版权声明:PDO防注入原理分析以及使用PDO的注意事项总结是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。