好文章不得不改成。使用PDO防注入的时光理应特别注意什么。

原文:http://zhangxugg-163-com.iteye.com/blog/1835721

咱们还懂得,只要合理正确用PDO,可以多防止SQL注入的有,本文主要对以下简单单问题:

吓章不得不改成。

为何而运用PDO而未是mysql_connect?

我们且知情,只要合理正确使用PDO,可以基本上防止SQL注入的起,本文主要回应以下简单单问题:

干什么而下PDO而不是mysql_connect?

何以PDO能防注入?

用PDO防注入的时刻理应特别注意什么?

 

一律、为何而优先采取PDO?

PHP手册上说得要命清楚:

Prepared statements and stored procedures
Many of the more mature databases support the concept of prepared
statements. What are they? They can be thought of as a kind of
compiled template for the SQL that an application wants to run, that
can be customized using variable parameters. Prepared statements offer
two major benefits: 

The query only needs to be parsed (or prepared) once, but can be
executed multiple times with the same or different parameters. When
the query is prepared, the database will analyze, compile and optimize
its plan for executing the query. For complex queries this process can
take up enough time that it will noticeably slow down an application
if there is a need to repeat the same query many times with different
parameters. By using a prepared statement the application avoids
repeating the analyze/compile/optimize cycle. This means that prepared
statements use fewer resources and thus run faster.

 

The parameters to prepared statements don’t need to be quoted; the
driver automatically handles this. If an application exclusively uses
prepared statements, the developer can be sure that no SQL injection
will occur(however, if other portions of the query are being built up
with unescaped input, SQL injection is still possible).

 

不畏采取PDO的prepare方式,主要是增强相同SQL模板查询性能、阻止SQL注入

再就是,PHP手册中吃起了警告信息

Prior to PHP 5.3.6, this element was silently ignored. The same behaviour can be partly replicated with the PDO::MYSQL_ATTR_INIT_COMMAND driver option, as the following example shows.
Warning

The method in the below example can only be used with character sets that share the same lower 7 bit representation as ASCII, such as ISO-8859-1 and UTF-8. Users using character sets that have different representations (such as UTF-16 or Big5) must use the charset option provided in PHP 5.3.6 and later versions.

 

意是说,在PHP
5.3.6以及以前版本被,并无支持于DSN中之charset定义,而该运用PDO::MYSQL_ATTR_INIT_COMMAND设置初始SQL, 即我们常用的 set names gbk指令。

 

本身见状局部先后,还在品尝以addslashes达到预防注入的目的,殊不知这样其实题材重新多,
详情请圈http://www.lorui.com/addslashes-mysql\_escape\_string-mysql\_real\_eascape\_string.html

还有一对做法:在执行数据库查询前,将SQL中的select, union,
….之类的根本词清理掉。这种做法显然是十分荒谬的处理方式,如果提交的正文中确实含有
the students’s union , 替换后以篡改本来之情节,滥杀无辜,不可取。

 

二、为何PDO能防SQL注入?
呼吁预押之下PHP代码:

<?php

$pdo = new PDO(“mysql:host=192.168.0.1;dbname=test;charset=utf8″,”root”);

$st = $pdo->prepare(“select * from info where id =? and name = ?”);

 

$id = 21;

$name = ‘zhangsan’;

$st->bindParam(1,$id);

$st->bindParam(2,$name);

 

$st->execute();

$st->fetchAll();

?>

 

条件如下:

PHP 5.4.7

Mysql 协议版本 10

MySQL Server 5.5.27

 

为干净整治懂php与mysql server通讯的细节,我特意利用了wireshark抓包进行研讨之,安装wireshak之后,我们装过滤条件也tcp.port==3306, 如下图:
图片 1
 

 

 

 

这般才展示与mysql 3306端口的通信数据,避免不必要之干扰。

专门要顾的是wireshak基于wincap驱动,不支持本地环回接口的侦听(即采用php连接本地mysql的法子是无能为力侦听的),请连接其他机器(桥接网络的虚拟机也只是)的MySQL进行测试。

 

下一场运行我们的PHP程序,侦听结果如下,我们发现,PHP只是略地以SQL直接发送给MySQL Server :

 

图片 2

 

 

 

实质上,这与我们平常运mysql_real_escape_string将字符串进行转义,再并入接成SQL语句没有距离(只是出于PDO本地驱动完成转义的),显然这种情景下还是发出或引致SQL注入的,也就是说在php本地调用pdo prepare中之mysql_real_escape_string来操作query,使用的是地方单字节字符集,而我们传递多配节编码的变量时,有或还是碰头招致SQL注入漏洞(php 5.3.6在先版本的题材之一,这为就算说了怎么在采用PDO时,建议升级至php 5.3.6+,并当DSN字符串中指定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 Server指定字符集,并将变量发送给MySQL Server完成因字符转义。

 

那,如何才能够禁止PHP本地转义而至由MySQL Server转义呢?

PDO有同码参数,名也PDO::ATTR_EMULATE_PREPARES ,表示是否动PHP本地模拟prepare,此桩参数默认值未知。而且根据我们正抓包分析结果来拘禁,php 5.3.6+默认还是采用当地变量转,拼接成SQL发送给MySQL Server的,我们以立刻项值设置也false, 试试效果,如以下代码:

<?php

$pdo = new PDO(“mysql:host=192.168.0.1;dbname=test;”,”root”);

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

 

$st = $pdo->prepare(“select * from info where id =? and name = ?”);

$id = 21;

$name = ‘zhangsan’;

 

$st->bindParam(1,$id);

$st->bindParam(2,$name);

$st->execute();

$st->fetchAll();

?>

 

红色行是咱们正好进入的内容,运行以下顺序,使用wireshark抓包分析,得出的结果如下:
图片 3
 

图片 4
 

 

看样子了也?这即是神奇的远在,可见这次PHP是以SQL模板与变量是劈点儿破发送给MySQL的,由MySQL完成变量的转义处理,既然变量和SQL模板是分点儿潮发送的,那么就算不设有SQL注入的题材了,但得在DSN中指定charset属性,如:

$pdo = new PDO(‘mysql:host=localhost;dbname=test;charset=utf8’, ‘root’);

 

然,即可从根本上杜绝SQL注入的问题。如果你针对这个不是杀懂,可以发邮件至zhangxugg@163.com, 一起探索。

 

其三、使用PDO的注意事项

了解以上几乎触及以后,我们不怕可以总结下PDO杜绝SQL注入的几只注意事项:

1.  php升级至5.3.6+,生产环境强烈建议升级到php 5.3.9+ php
5.4+,php 5.3.8在致命之hash碰撞漏洞。

 

  1. 若使用php 5.3.6+, 请在在PDO的DSN中指定charset属性

  2. 要是使用了PHP
    5.3.6跟以前版本,设置PDO::ATTR_EMULATE_PREPARES参数为false(即出于MySQL进行变量处理),php
    5.3.6以上版本就处理了之题目,无论是以当地模拟prepare还是调用mysql
    server的prepare均只是。在DSN中指定charset是无效的,同时set names
    <charset>的尽是少不了的。

 

4. 假设运用了PHP 5.3.6与以前版本,
因Yii框架默认并未设置ATTR_EMULATE_PREPARES的价,请于数据库配置文件中指定emulatePrepare的值也false。

 

那么,有只问题,如果以DSN中指定了charset, 是否还需要实践set names
<charset>呢?

科学,不能够看。set names <charset>其实产生三三两两单作用:

A.  告诉mysql server, 客户端(PHP程序)提交给其的编码是啊

B.  告诉mysql server, 客户端需要的结果的编码是什么

也就是说,如果数据表使用gbk字符集,而PHP程序用UTF-8编码,我们当履查询前运行set
names utf8, 告诉mysql
server正确编码即可,无须在次中编码转换。这样我们盖utf-8编码提交查询及mysql
server,
得到的结果为会见是utf-8编码。省却了先后中之变换编码问题,不要生疑难,这样做不会见发出乱码。

 

那么在DSN中指定charset的企图是呀? 只是喻PDO,
本地驱动转义时行使指定的字符集(并无是设定mysql
server通信字符集),设置mysql server通信字符集,还得用set names
<charset>指令。

 

比方图片丢失,可以发邮件至zhangxugg@163.com, 索取PDF版本。

 

我真的想不通,一些初的花色,为何不下PDO而使用传统的mysql_XXX函数库呢?如果对行使PDO,可以从根本上杜绝SQL注入,我强烈建议各个企业之技术官员、一线技术研发人员,要对准斯题目引起重视,尽可能采取PDO加快项目进度和安康质量。

 

甭再次尝试自己编写SQL注入过滤函数库了(又烦而好轻有未知之狐狸尾巴)。

为什么PDO能防注入?

 

使PDO防注入的时光应该特别注意什么?

一如既往、为何设先行采取PDO?

PHP手册上说得很了解:

复制代码 代码如下:

Prepared statements and stored procedures
Many of the more mature databases support the concept of prepared
statements. What are they? They can be thought of as a kind of compiled
template for the SQL that an application wants to run, that can be
customized using variable parameters. Prepared statements offer two
major benefits:

The query only needs to be parsed (or prepared) once, but can be
executed multiple times with the same or different parameters. When the
query is prepared, the database will analyze, compile and optimize its
plan for executing the query. For complex queries this process can take
up enough time that it will noticeably slow down an application if there
is a need to repeat the same query many times with different parameters.
By using a prepared statement the application avoids repeating the
analyze/compile/optimize cycle. This means that prepared statements use
fewer resources and thus run faster.

The parameters to prepared statements don’t need to be quoted; the
driver automatically handles this. If an application exclusively uses
prepared statements, the developer can be sure that no SQL injection
will occur(however, if other portions of the query are being built up
with unescaped input, SQL injection is still possible).

 

就算用PDO的prepare方式,主要是增高相同SQL模板查询性能、阻止SQL注入

同时,PHP手册中叫来了警告信息

复制代码 代码如下:

Prior to PHP 5.3.6, this element was silently ignored. The same
behaviour can be partly replicated with the
PDO::MYSQL_ATTR_INIT_COMMAND driver option, as the following example
shows.
Warning
The method in the below example can only be used with character sets
that share the same lower 7 bit representation as ASCII, such as
ISO-8859-1 and UTF-8. Users using character sets that have different
representations (such as UTF-16 or Big5) must use the charset option
provided in PHP 5.3.6 and later versions.

意思是说,在PHP
5.3.6与以前版本中,并无支持于DSN中的charset定义,而相应采取PDO::MYSQL_ATTR_INIT_COMMAND设置初始SQL,
即我们常常因此之 set names gbk指令。

本身瞅有序,还以品尝用addslashes达到防止注入的目的,殊不知如此事实上问题还多,
详情请看http://www.lorui.com/addslashes-mysql_escape_string-mysql_real_eascape_string.html

还有一部分做法:在推行数据库查询前,将SQL中的select, union,
….之类的重中之重词清理掉。这种做法显然是很错误的处理方式,如果提交的正文中真的含有
the students’s union , 替换后拿篡改本来之始末,滥杀无辜,不可取。

二、为何PDO能防SQL注入?
要预看以下PHP代码:

复制代码 代码如下:

<?php
$pdo = new
PDO(“mysql:host=192.168.0.1;dbname=test;charset=utf8″,”root”);
$st = $pdo->prepare(“select * from info where id =? and name =
?”);
$id = 21;
$name = ‘zhangsan’;
$st->bindParam(1,$id);
$st->bindParam(2,$name);
$st->execute();
$st->fetchAll();
?>

条件如下:

PHP 5.4.7

Mysql 协议版本 10

MySQL Server 5.5.27

以干净为懂php与mysql
server通讯的细节,我特别以了wireshark抓包进行研讨的,安装wireshak之后,我们设置过滤条件为tcp.port==3306,
如下图:

图片 5

然才展示与mysql 3306端口之通信数据,避免不必要之搅和。

专程而留意的凡wireshak基于wincap驱动,不支持地方环回接口的侦听(即以php连接本地mysql的主意是无力回天侦听的),请连接其他机器(桥接网络的虚拟机也只是)的MySQL进行测试。

然后运行我们的PHP程序,侦听结果如下,我们发现,PHP只是简短地以SQL直接发送给MySQL
Server :

图片 6

实则,这与我们平常使mysql_real_escape_string将字符串进行转义,再并入接成SQL语句没有区别(只是由于PDO本地驱动完成转义的),显然这种景象下还是来或导致SQL注入的,也就是说在php本地调用pdo
prepare中之mysql_real_escape_string来操作query,使用的是地面单字节字符集,而我们传递多字节编码的变量时,有或还是碰头招致SQL注入漏洞(php
5.3.6先版本的题材之一,这为就算说了怎么在行使PDO时,建议升级至php
5.3.6+,并在DSN字符串中指定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 Server指定字符集,并以变量发送给MySQL
Server完成因字符转义。

这就是说,如何才会禁止PHP本地转义而到由MySQL Server转义呢?

PDO有同一码参数,名吧PDO::ATTR_EMULATE_PREPARES
,表示是否动PHP本地模拟prepare,此起参数默认值未知。而且因我们恰好抓包分析结果来拘禁,php
5.3.6+默认还是用当地变量转,拼接成SQL发送给MySQL
Server的,我们将马上项值设置也false, 试试效果,如以下代码:

复制代码 代码如下:

<?php
$pdo = new PDO(“mysql:host=192.168.0.1;dbname=test;”,”root”);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$st = $pdo->prepare(“select * from info where id =? and name =
?”);
$id = 21;
$name = ‘zhangsan’;
$st->bindParam(1,$id);
$st->bindParam(2,$name);
$st->execute();
$st->fetchAll();
?>

红行是我们刚刚投入的内容,运行以下顺序,使用wireshark抓包分析,得出的结果如下:

图片 7

图片 8

看了呢?这便是神奇的远在,可见这次PHP是将SQL模板与变量是分开点儿潮发送给MySQL的,由MySQL完成变量的转义处理,既然变量和SQL模板是分开点儿不行发送的,那么尽管非在SQL注入的问题了,但需要在DSN中指定charset属性,如:

复制代码 代码如下:

$pdo = new PDO(‘mysql:host=localhost;dbname=test;charset=utf8’,
‘root’);

诸如此类,即可从根本上杜绝SQL注入的题目。如果你针对这不是异常懂得,可以发邮件至zhangxugg@163.com,
一起探究。

其三、使用PDO的注意事项

懂得以上几乎沾之后,我们虽得总结运用PDO杜绝SQL注入的几乎只注意事项:

1.  php升级到5.3.6+,生产条件强烈建议升级至php 5.3.9+ php 5.4+,php
5.3.8有致命的hash碰撞漏洞。

  1. 若使用php 5.3.6+, 请在在PDO的DSN中指定charset属性

  2. 倘运用了PHP
    5.3.6暨以前版本,设置PDO::ATTR_EMULATE_PREPARES参数为false(即出于MySQL进行变量处理),php
    5.3.6以上版本已经处理了之题目,无论是以当地模拟prepare还是调用mysql
    server的prepare均只是。在DSN中指定charset是无济于事的,同时set names
    <charset>的尽是少不了的。

  3. 若果下了PHP 5.3.6与以前版本,
    因Yii框架默认并未设置ATTR_EMULATE_PREPARES的价,请于数据库配置文件被指定emulatePrepare的值也false。

那,有只问题,如果当DSN中指定了charset, 是否还欲实施set names
<charset>呢?

没错,不可知省。set names <charset>其实产生三三两两独作用:

A.  告诉mysql server, 客户端(PHP程序)提交给它的编码是啊

B.  告诉mysql server, 客户端需要的结果的编码是什么

也就是说,如果数据表使用gbk字符集,而PHP程序采取UTF-8编码,我们在实行查询前运行set
names utf8, 告诉mysql
server正确编码即可,无须在次中编码转换。这样咱们因为utf-8编码提交查询到mysql
server,
得到的结果吗会是utf-8编码。省却了次中的转换编码问题,不要闹疑点,这样做不会见生乱码。

那么在DSN中指定charset的意向是啊? 只是告PDO,
本地驱动转义时利用指定的字符集(并无是设定mysql
server通信字符集),设置mysql server通信字符集,还得下set names
<charset>指令。

自己真的想不通,一些初的档次,为何无使用PDO而使用传统的mysql_XXX函数库呢?如果是采取PDO,可以从根本上杜绝SQL注入,我强烈建议各个公司之技术官员、一丝技术研发人员,要对这问题引注重,尽可能使用PDO加快项目进度与安质量。

不要再品尝自己编辑SQL注入过滤函数库了(又麻烦而很易生出未知的尾巴)。

以上就是是本文的全部内容了,希望小伙伴等会出色读毕,十分实用。

您可能感兴趣之文章:

  • PHP PDO函数库详解
  • PHP5中应用PDO连接数据库的措施
  • Jquery中之CheckBox、RadioButton、DropDownList的取值赋值实现代码
  • ASP.NET jQuery 实例7
    通过jQuery来获取DropDownList的Text/Value属性值
  • mysql,mysqli,PDO的分级不同介绍
  • asp.net中不克在DropDownList中摘多只项
    原因剖析及解决措施
  • ASP.NET MVC
    DropDownList数据绑定及用详解
  • Php中之所以PDO查询Mysql来避免SQL注入风险的章程
  • Jquery操作下拉框(DropDownList)实现取值赋值
  • JS获取DropDownList的value值与text值的示范代码
  • php使用pdo连接sqlserver示例分享
  • PHP PDO操作总结
  • php使用PDO方法详解