tkcharlotte's blog

测试时发现的一点小问题。

所谓的隐式类型转换,就是在不使用转换函数的情况下,默认转换了类型,比方说定义一个varchar变量id,传入了一个非预期类型的值,就会转换类型然后带入语句查询。说到底是忽略了不同数据类型之间是否兼容。

隐式类型转换有时会导致无法使用索引的风险,尤其是在高并发的情况下,不走索引就会全盘搜索,进行N多次I/O操作,占用很多资源而且浪费时间。

规则

看一下转换规则:

mysql官方文档

翻译过来的规则如下(半机翻):

  • 如果是一个或两个参数NULL,则比较的结果是NULL,除了NULL-safe <=> 等式比较运算符。因为NULL <=> NULL,结果是真的。无需转换。
  • 如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。
  • 如果两个参数都是整数,则将它们作为整数进行比较。
  • 如果不与数字进行比较,十六进制值将被视为二进制字符串。
  • 如果其中一个参数是TIMESTAMPDATETIME列而另一个参数是常量,则在执行比较之前将常量转换为时间戳。
  • 有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较.
  • 所有其他情况下,两个参数都会被转换为浮点数再进行比较.

测试实例

test_table表中有username字段,varchar类型

正常情况下:

当我们输入0时,

会返回全部的数据,这是为什么?

看上边的规则,最后一条,其他情况下,会转换成浮点数进行比较,字符串转浮点数会失败,就像php弱类型一样,mysql有没有类似的机制呢?尝试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mysql> select 1='aaa',1='1aaa',1='2aaa',1='123aaa',1=1.0;
+---------+----------+----------+------------+-------+
| 1='aaa' | 1='1aaa' | 1='2aaa' | 1='123aaa' | 1=1.0 |
+---------+----------+----------+------------+-------+
| 0 | 1 | 0 | 0 | 1 |
+---------+----------+----------+------------+-------+
1 row in set, 4 warnings (0.00 sec)

mysql> select 1='aaa',1='1aaa',2='2aaa',123='123aaa',1=1.0;
+---------+----------+----------+--------------+-------+
| 1='aaa' | 1='1aaa' | 2='2aaa' | 123='123aaa' | 1=1.0 |
+---------+----------+----------+--------------+-------+
| 0 | 1 | 1 | 1 | 1 |
+---------+----------+----------+--------------+-------+
1 row in set, 4 warnings (0.00 sec)

mysql> select 2 = 'a2';
+----------+
| 2 = 'a2' |
+----------+
| 0 |
+----------+
1 row in set, 1 warning (0.00 sec)

从上边可以看出,字符串转成浮点数时会失败,如果字符串开头为数字,会在字母处截断,只取数字作为转换后的结果,所以username=0时会返回所有的结果,因为插入的数据都不是以数字开头的,转换时都会转成0,0=0,满足条件所以输出。

sql注入中的利用

查了查资料,有大佬已经总结过了,陕西省网络安全大赛中出过一道这样的题目,详情可以看这里

参考链接

https://dev.mysql.com/doc/refman/5.7/en/type-conversion.html

https://www.anquanke.com/post/id/86021

https://www.cnblogs.com/rollenholt/p/5442825.html

 评论


载入天数...载入时分秒... | 字数统计:14.4k