先来看下这段sql
$query = 'SELECT * from user where name =" '.$name.' "';
这样的sql是我们经常有写的,
然后$name = ' ";delete from user where name="mini -- ";';
这里' 后面跟一个空格,其实没有,是wile看的更清楚些
如此,这就是是一个sql注入,先截断了我们定义好的"符号,自定义一个"使之于我们定义好的第一个"配对,这样后面的输入串,就非一个sql字符串了,就成功完成sql注入
这种截断引号的注入方式非常常见,当然引号包括单引号于双引号,注入者,必须要完成与sql语句的前一个引号,成功配对,才可能完成注入,这里所说的成功配置指的是,如果 我们这里
where name =" ' .$name. ' " 注入者,就必须只有用"号才能成功配对,截断本该是字符串的参数,
如果这块是 where name =' " .$name. " ' 单引号来标识的字符串,那么注入者,只可能用单引号来截断,完成注入
注意上面提到的sql语句,变量拼接语法所涉及到的单引号或双引号,这只是语法形式,拼接完成后,并不会保留
前面说到的是,截断引号方式的注入方法,还有一种是根本不需要截断引号就可以完成注入的方式,
比如说,如下sql
$query = 'SELECT * from '.$user.' where name ="zhangyan" ';
其中$user = 'user;delete from user where name="mini";--';
如此这个变量本来就不在一个字符串中,当然,注入时,不用引号配对来截断,直接;结束上一个sql然后写我们的注入sql语句就ok
所以,有效的避免sql注入,并不仅仅是在where条件后。
如何来有效的避免sql注入呢,
这里只说pdo,
1.首先pdo提供quote方法,来转义所有的输入的参数
但是使用quote方法需要注意的是,它认为所有输入的参数都是字符串形式输出,所以在拼接sql是,自定义的sql语句就不用在加上 字符串表示符了(单引号或者双引号) 比如说where name ='.$name
直接如此就ok 。这里出现的单引号是为了拼接变量的语法形式,并不是字符串中的引号
2.第二种方式是使用prepare来于执行你的sql语句,之后再进行填充你的输入参数,以此来保证不会出现截断整体sql的行为,但并不是说sql语句就完全能够防止sql注入,比如如下
$prepareSql = 'SELECT * from '.$user.' where name =:name';
$sth = $dbh->prepare($prepareSql);
$sth->execute(array(':name' => 'zhangsan'));
这里的$user 还是和之前一样 $user = 'user;delete from user where name="mini";--';
这样在预执行的时候,sql注入就已经发生了,网上都说pdo能够防止sql注入,这完全是不对的说法,
其实是否能完全防止sql语句,在于你是怎样用 的,比如说,我们把所有的输入参数,都经过转义后,才拼接到sql语句中,如果是用prepare,我们把所有输入参数都放在execute中,而不是拼接在prepare时,如此就能有效的防范sql注入,
其实关于网上说pdo能够防止sql注入,这句话应该这样说,pdo能够提供给更好的方法来防止sql注入。
其他链接数据库方式,只要做好输入字段的转义工作,也一样能够有效的防止sql的注入
其实所谓字段的转义工作,在sql语句里面,可以参照于pdo的quote方法,吧所有输入字段都当做字符串的输出,并且对所有引号进行转义,这样就能有效的防止,sql语句的注入。
3.对整个sql语句进行直接转义。
也许你回这样想,直接对整个sql语句进行转义,这样就开发者就不用单独提出所输入的字段了,也许你没这样想过,但至少我这样想过,但是这种方式是不对的,如下
这里就不以脚本的形式表现了,直接是sql语句形式
SELECT * from user where name = /"zh/"angyan/"
如果是对整个sql语句进行直接转义,最终发送给mysql的就是这样一句sql。
可以执行下,就知道,失败。
因为第一次转义和第二次转义的",正好会完成引号的配对,这样后面的字符就不是一种字符串方式了,在此之前,sql语句已经被截断,也就是说这种方式,是不会解决sql注入的。
最后总结一句:想从根本上解决sql注入,其实在于开发者的个人意识,根本上说什么框架不能完美的解决这个问题,即使是从框架方法解决,开发者也必须要把输入数据按照框架的约定放在我特定的规则里面,才能完美的解决sql注入隐患。