目前国内对PHP+MySQL注入关注的人很少。PHP的安全性本身就比ASP要好的多,加上MySQL 4.0一下的版本是不支持子语句的,而且当php.ini里的magic_quotes_gpc被设置为on时,提交的变量中所有的单引号,双引号,反斜线和空字符会自动转义为含有反斜线的转义字符,又给注入带来不少阻碍。

早起大家玩PHP+MySQL注入时,根据程序代码要构造出没有引号的语句而形成有效的攻击,还真的有点困难,好在现在的技术已经可以构造出不带单引号的语句应用在某些场合。只要有经验,构造有效的语句其实一点也不难。

首先大家要走出一个误区,很多人在PHP+MySQL下注入一定要用到单引号,或者是没有办法像SQL Server那样可以使用“declare @a sysname select @a=<command> exec master.dbo.xp_cmdshell@a” 这类的命令来消除引号,其实这是大家对注入的一种误解。因为不管什么语言在引号里,所有字符串均是常量。即使是dir这样的命令,也仅仅是字符串而已,而不是当作命令来执行的,除非是这样写的代码:

$command = " dir c:\";

system($command);

当然,这里所说的命令不单指系统命令,还有包含SQL语句,要让构造的SQL语句正常执行,就不能让语句变成字符串,那么什么情况下用单引号,什么时候不用呢?看看下面的两个SQL语句:

SELECT * FROM article WHERE articleid='$id';

SELECT * FROM article WHERE articleid=$id;

这两种写法在各种程序中都很普遍,但安全性是不同的:第一句由于把变量$id放在一对单引号中,这样使得所提交的变量都变成了字符串,即使包含了正确的SQL语句,也不会被正常执行;而第二句则不同,由于没有把变量放进单引号中,那么所提交的一切,只要包含空格,那空格之后的变量都会被作为SQL语句执行。针对这两个语句,分别提交两个成功注入的语句,来看看他们的不同之处:

指定变量$id为:

1’ and 1=2 union select * from user where userid=1/*

此时整个SQL语句变为:

SELECT * FROM article WHERE articleid='1' and 1=2 union selec * from user where userid=1/*'

指定变量$id为:

1 and 1=2 union select * from user where userid=1

此时整个SQL语句变为:

SELECT * FROM article WHERE articleid=1 and 1=2 union select * from user where userid=1

看出来了吗?由于第一句有单引号,所以必须先闭合前面的单引号才能使后面的语句作为SQL语句执行,并且要注释掉原SQL语句后面的单引号,这样才可以成功注入。但如果php.ini中magic_quotes_gpc被设置为on或者变量前使用了addslashes()函数,注入就会失败。但第二句没有用单引号包含变量,那么就不用考虑闭合、注释等,直接提交语句就可以了。