宝哥软件园

PDO防注入原理分析以及注意事项

编辑:宝哥软件园 来源:互联网 时间:2021-10-13

我们都知道,只要合理正确使用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指令。

我看到一些程序,还在尝试使用添加斜线达到防注入的目的,殊不知这样其实问题更多,详情请看http://www .洛瑞。com/add slashes-MySQL _ escape _ string-MySQL _ real _ eascape _ string。超文本标记语言

还有一些做法:在执行数据库查询前,将结构化查询语言中的选择,联合,之类的关键词清理掉。这种做法显然是非常错误的处理方式,如果提交的正文中确实包含学生会,替换后将篡改本来的内容,滥杀无辜,不可取。

二、为何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.7

关系型数据库协议版本10

关系型数据库服务器5.5.27

为了彻底搞清楚服务器端编程语言(专业超文本预处理器的缩写)与关系型数据库服务器通讯的细节,我特别使用了wireshark抓包进行研究之,安装wireshak之后,我们设置过滤条件为tcp.port==3306,如下图:

如此只显示与mysql 3306端口的通信数据,避免不必要的干扰。

特别要注意的是wireshak基于wincap驱动,不支持本地环回接口的侦听(即使用服务器端编程语言(专业超文本预处理器的缩写)连接本地关系型数据库的方法是无法侦听的),请连接其它机器(桥接网络的虚拟机也可)的关系型数据库进行测试。

然后我们运行我们的PHP程序,监听结果如下。我们发现PHP只是把SQL直接发送到MySQL Server :

实际上,这与我们通常使用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。

对于5.3.6之前的PHP版本,以下代码仍可能导致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-prepare('从信息中选择*其中id=?和名称=?”);$ id=21$ name=' zhangsan$st-bindParam(1,$ id);$st-bindParam(2,$ name);$ ST-execute();$ ST-Fetchall();

红线是我们刚刚添加的内容。运行以下程序并使用wireshark捕获包后,结果如下:

看到了吗?这就是神奇之处。可以看到,PHP这次两次将SQL模板和变量发送给MySQL,MySQL完成了变量的转义处理。由于变量和SQL模板被发送了两次,所以不存在SQL注入问题,但是需要在DSN中指定字符集属性,例如:

复制代码如下: $ PDO=newpdo(' 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 _ emulate _ prepares设置为false(即mysql处理变量),那么PHP 5.3.6及以上版本已经处理了这个问题,无论是使用本地模拟prepare还是调用MySQL服务器prepare。在DSN中指定字符集是无效的,集名字符集的执行是必不可少的。

4.如果使用PHP 5.3.6和以前的版本,由于Yii框架默认不设置ATTR _仿真_准备的值,请在数据库配置文件中将仿真准备的值指定为false。

那么,有一个问题,如果在DSN中指定了字符集,还需要执行集名字符集吗?

是的,我不能。字符集实际上有两个功能:

A.告诉mysql服务器客户端(PHP程序)向它提交了什么代码。

B.告诉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注入过滤器库(这很繁琐,容易产生未知的漏洞)。

这就是本文的全部内容。希望朋友们能好好读一读。非常实用。

更多资讯
游戏推荐
更多+