来看看表的结构:
mysql> show create table zzz;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| zzz | CREATE TABLE `zzz` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`score` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
表内容:
mysql> select * from zzz;
+----+-------+----------+-------+
| id | name | password | score |
+----+-------+----------+-------+
| 1 | taoge | 123 | 100 |
+----+-------+----------+-------+
1 row in set (0.00 sec)
mysql>
要说明的是, 把密码明文存储起来, 本身就是不安全的。 即使用密文存储, 也不安全, 应该考虑用加盐哈希。 但本文为了简便起见, 先不讨论这个问题。
现在假设有一个页面, 需要用户输入name和password, 然后查询score的值, 页面请求发送到后台, 后台查询伪代码为:
string strName = ... ;
string strPassword = ... ;
select * from zzz where name=strName and password=strPassword ...
此时,如果taoge自己查询, 那么输入name(taoge)和password(123)后, 执行的查询操作是:
mysql> select * from zzz where name='taoge' and password='123';
+----+-------+----------+-------+
| id | name | password | score |
+----+-------+----------+-------+
| 1 | taoge | 123 | 100 |
+----+-------+----------+-------+
1 row in set (0.00 sec)
mysql>
可以正确查到自己的分数, 合情合理。
但是, 上面的代码有sql注入风险, 假设Jack想查询taoge的分数, 但又不知道taoge的密码, 怎么办呢? 还是可以查询到的: Jack在页面分别输入
用户名: taoge' or 1 = 1 ; #
密码:hehe
那么, 经页面传到后台后, 后台执行的操作是:
mysql> select * from zzz where name='taoge' or 1 = 1 ; #' and password='hehe';
+----+-------+----------+-------+
| id | name | password | score |
+----+-------+----------+-------+
| 1 | taoge | 123 | 100 |
+----+-------+----------+-------+
1 row in set (0.00 sec)
可见, 即使Jack不知道taoge的密码123, 也是可以通过sql注入的方式得逞的。 在上面语句中, #充当了注释符号的作用, 而1=1永远为真, 所以,这相当于绕过了后台的密码校验逻辑。
后台系统该怎么对抗这种sql注入攻击呢?
1. 对每个参数进行严格校验
2. mysql_real_escape_string搞起
3. 防缓冲区溢出
......
有关sql的注入攻击, 后面也会继续介绍。