最近看恶心代码太多了,也写了太多垃圾代码了……真是哦弥陀佛……感觉paperen变垃圾……

唉~~不多说了,直接开始正文算了。放代码,对比一下下面两个sql变量,然后入库查询,你觉得有问题么?

$id = isset($_GET['id']) ? $_GET['id'] : '';
if ($id) {
$sql = 'select * from goods where id='.$id;
echo $sql.'
';

$r_1 = $db->select($sql);
print_r($r_1);

echo '----
';

$sql = "select * from goods where id='$id'";
echo $sql.'
';

$r_2 = $db->select($sql);
print_r($r_2);

echo '----
';
}

表面上看上去都是可以的,当test.php?id=1时输出sql这个变量都是一样的,但是如果我随意改变一下这个id呢?改为test.php?id=1 or 1=1,你就会看到区别了。

第一个$sql变为:select * from goods where id=1 or 1=1

第二个$sql变为:select * from goods where id='1 or 1=1'

很明显当将前一个sql语句送入数据库后,都会查询出goods表中所有记录的,因为加上了or 1=1,也就是永远都是真的。而第二条sql则将1 or 1=1当为一个字符串与表中的id号匹配,由于mysql的机制会自动将这段字符串中前面数字部分进行匹配(确实这里会有点费解,其实与id='1'是相同效果,不过这里的id字段必须是数字类型),所以这里的sql等同于“select * from goods where id='1'”,所以还是查到id为1的数据。

而万恶之源也正是这样衍生出来的,特别是一些新手对于这种处理get数值的时候可能就会犯下错误。很明显地,第一句sql是对get过来的数据想都不想就直接与我们写好的一部分sql语句拼合起来,然后扔去给数据库处理,故会出现一些我们意想不到的结果,例如能查出这个表的所有数据还可以结合union等其他命令去注入我们的数据库(这种事情就是黑客所说的注入点)。如果我这个数据库中还有一个user表装的是管理员的登陆信息的话,这里事先告诉你user表有3个字段,分别是id,username,password,而goods表有9个字段。如果你用的第一种写法我们就有可能通过这里获得你管理员表的信息。

sql1:select * from goods where id=1 union select 1,2,3,4,5,6,7,8,9 from user

sql2:select * from goods where id='1 union select 1,2,3,4,5,6,7,8,9 from user'

sql1 result:

Array
(
[0] => Array
(
[id] => 1
[price] => 0.40
[cost] => 1
[name] => 香蕉
[luckyprice] => 0.01
[start] => 2010-09-15 09:02:05
[end] => 2010-09-16 09:01:07
[auctionnum] => 5
[expectnum] => 45
)

[1] => Array
(
[id] => 1
[price] => 2.00
[cost] => 3
[name] => 4
[luckyprice] => 5.00
[start] => 6
[end] => 7
[auctionnum] => 8
[expectnum] => 9
)

sql2 result:

Array
(
[0] => Array
(
[id] => 1
[price] => 0.40
[cost] => 1
[name] => 香蕉
[luckyprice] => 0.01
[start] => 2010-09-15 09:02:05
[end] => 2010-09-16 09:01:07
[auctionnum] => 5
[expectnum] => 45
)

)

20100917203402

sql1抽取的数据中多了一组数据,正是1,2,3,4,5,6,7,8,9,而出来的数据类型与goods表一致,so,当我再猜测user表中用户名那个字段是username时

select * from goods where id=1 union select 1,2,3,username,5,6,7,8,9 from user

Array
(
[0] => Array
(
[id] => 1
[price] => 0.40
[cost] => 1
[name] => 香蕉
[luckyprice] => 0.01
[start] => 2010-09-15 09:02:05
[end] => 2010-09-16 09:01:07
[auctionnum] => 5
[expectnum] => 45
)

[1] => Array
(
[id] => 1
[price] => 2.00
[cost] => 3
[name] => paperen //注意这里
[luckyprice] => 5.00
[start] => 6
[end] => 7
[auctionnum] => 8
[expectnum] => 9
)
)

如果我又猜中了放密码的那个字段为password不就同样可以查出来了。

很显然这是我们意想不到的结果,本来就是想查一张商品表没想到反被人连管理员都查出来了。所以千万不要相信来自客户端的数据,这是真理。

最后,paperen还是叮嘱一句最好也对这个get来的id进行一下类型转换,既然肯定是一个数字,可以使用intval函数或者is_numeric检查一下。