小伙伴想精准查找自己想看的MySQL文章?喏 → MySQL江湖路 | 专栏目录

  我相信90%以上的同学们在平时开发时,或多或少都被隐式转换(CONVERT_IMPLICIT)坑过,甚至测出bug前你都浑然不知。你还别不信,“无形之刃,最为致命!”

这不,我们公司侨总今天又出来现眼了~

大家好,我是陈哈哈的同事“侨总”,领导一般不敢喊我名字,都叫我小侨~

mysql> SELECT * from t_user;
+----+-----------+----------+
| id | username  | password |
+----+-----------+----------+
|  1 | 陈哈哈    | abcd1234 |
|  2 | 侨布斯    | 1234     |
|  3 | 提莫      | 1234abcd |
+----+-----------+----------+
3 rows in set (0.00 sec)

  不能展示真实数据,见谅~~ 上面是这张用户表的原始数据,侨总用下面的SQL查询自己这行数据,大家先看看有没有问题?

SELECT * from t_user where `password`=1234;

感觉没有明显的毛病?来看看结果:

mysql> SELECT * from t_user where `password`=1234;
+----+-----------+----------+
| id | username  | password |
+----+-----------+----------+
|  2 | 侨布斯    | 1234     |
|  3 | 提莫      | 1234abcd |
+----+-----------+----------+
2 rows in set, 1 warning (0.00 sec)

  ???这怎么把提莫队长给打现行了?侨总看着他写的SQL,像小女生般羞涩的的笑出了声,好像内裤的颜色被大家们看到了一样~

  好了,其实这算是MySQL给开发者留下的不友好的礼物(坑)。今天我们一起从以下三个角度去聊一聊MySQL的隐式转换。

  来不及了,快上车!

索引

  • 1、SQL语句中隐式转换的坑
  • 2、黑客同学喜欢用隐式转换进行SQL注入攻击
  • 3、索引中隐式转换的坑
  • 总结
  • 附、一张有故事的照片(十七)

1、SQL语句中隐式转换的坑

先看一下官方的隐试转换说明:

翻译成人话:

  1. 两个参数至少有一个是 NULL 时,比较的结果也是 NULL,例外是使用 <=> 对两个 NULL 做比较时会返回 1,这两种情况都不需要做类型转换。
  2. 两个参数都是字符串,会按照字符串来比较,不做类型转换
  3. 两个参数都是整数,按照整数来比较,不做类型转换
  4. 十六进制的值和非数字做比较时,会被当做二进制串
  5. 有一个参数是 TIMESTAMP 或 DATETIME,并且另外一个参数是常量,常量会被转换为 timestamp
  6. 有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
  7. 所有其他情况下,两个参数都会被转换为浮点数再进行比较。(这里所说的浮点数一般默认为double类型)

  可以看到,非前六种以外的类型转换都要转成浮点类型来处理,这意味着什么?意味着MySQL承认了隐式转换这个事儿,还表示不爱看官方文档的哥们儿出问题活该~~

  我们用一些具体示例来看一下,通过下述SQL可见,当1234没有引号也就是整数时,‘1234abcd’ = 1234 → true,说明MySQL对’1234abcd’做了转型,转成了浮点类型,结果是:1234abcd => 1234

# 0:false;1:true
mysql> SELECT '1234abcd' = '1234';
+---------------------+
| '1234abcd' = '1234' |
+---------------------+
|                   0 |
+---------------------+
1 row in set (0.00 sec)# 0:false;1:true
mysql> SELECT '1234abcd' = 1234;
+-------------------+
| '1234abcd' = 1234 |
+-------------------+
|                 1 |
+-------------------+
1 row in set, 1 warning (0.00 sec)

  为啥1234abcd => 1234呢? 其实’1234’和’abcd’都会转成浮点数,即:1234+0=1234,非数字类型的都被直接转成了 0

mysql> SELECT '1234' + 'abcd';
+-----------------+
| '1234' + 'abcd' |
+-----------------+
|            1234 |
+-----------------+
1 row in set, 1 warning (0.00 sec)

  你发现了什么?原来字符串涉及到 +=-/ 等等运算符时都会进行隐式转型,也就是转成double,那么字符串转double是怎么转的呢?

# 转成:'1aaaa' = 1
mysql> SELECT '1aaaa' = 1;
+-------------+
| '1aaaa' = 1 |
+-------------+
|           1 |
+-------------+
1 row in set, 1 warning (0.00 sec)# 转成:'a1111' = 0
mysql> SELECT 'a1111' = 1;
+-------------+
| 'a1111' = 1 |
+-------------+
|           0 |
+-------------+
1 row in set, 1 warning (0.00 sec)# 转成:0 + 0 =0
mysql> SELECT 'aa' + 'aa' = 1;
+-----------------+
| 'aa' + 'aa' = 1 |
+-----------------+
|               0 |
+-----------------+
1 row in set, 2 warnings (0.00 sec)# 转成:0 + 0 + 1 =1
mysql> SELECT 'aa' + 'aa' + '1' = 1;
+-----------------------+
| 'aa' + 'aa' + '1' = 1 |
+-----------------------+
|                     1 |
+-----------------------+
1 row in set, 2 warnings (0.00 sec)

  可见,是以字符串从左向右取值的,且从非数字起后面的值都被转成 0,如a11111,第一位为a,则整体转为 01aaaa第一位为1,第二位为a,从第二位往后转成0,得a111110

mysql> SELECT * from t_user where `password`=1234;
+----+-----------+----------+
| id | username  | password |
+----+-----------+----------+
|  2 | 侨布斯    | 1234     |
|  3 | 提莫      | 1234abcd |
+----+-----------+----------+
2 rows in set, 1 warning (0.00 sec)

  现在我们就明白为什么能匹配到提莫了。因为在不同类型转换时"1234abcd"被转成了浮点类型,"abcd"转成浮点型后为0,因此MySQL判为:“1234abcd” = ‘1234’ + 0 。

2、黑客同学喜欢用隐式转换进行SQL注入攻击

通过第一部分隐式转换的了解,我们可以预测一些简单SQL注入的方式:

mysql> SELECT * from t_user where username='陈哈哈' and `password`=0;
+----+-----------+----------+
| id | username  | password |
+----+-----------+----------+
|  1 | 陈哈哈    | abcd1234 |
+----+-----------+----------+
1 row in set, 1 warning (0.00 sec)

果然,我账号的密码被毫无意外的攻破了。。。想想账号被陌生人登录,保存多年的情书也会被泄露出去~~

如果有些朋友公司的网站用的是下面的写法:

select * from t_user where username=${username} and `password`=${password};

  不然有些小伙伴友好的把请求参数构建成 username → a' OR 1='1 ,那么password是啥都无所谓了,是吧。

懂我意思吧,快改了。

  当然,其实很多注入攻击的真实目的,并不是用来破解用户账号的,而是破坏服务器。一般我们在页面F12发现有问题的接口后,通过脚本模拟请求参数(构造注入参数),去不断尝试自定义构造limit、order、where等条件,或许花不了多久就能通过一个不规范的请求入口,检索出该表甚至其他大表全量信息。导致公司服务器负载异常,连接数打满,CPU200%等有趣的情况。有兴趣的同学可以花几小时尝试破解自己公司的web~~

3、索引中隐式转换的坑

  同理,在MySQL根据索引进行查询时,如果你的username字段有索引且为varchar类型,且查询如下时:

select * from t_user where username=123;

该SQL会出现两个问题:

1、索引失效
  无法使用到索引查询,因为mysql会在引擎层进行类型隐式转换(CONVERT_IMPLICIT),会先把username隐式转换成浮点数,然后再跟你的123进行比较,然而你的索引是建在username上的,并不是在转换后的username上的,所以进行转换后的username相当于没有索引。会全表扫描,换做大表中,无法使用索引,你懂得。

2、查询结果不准确
  第一部分我们已经举例说明,MySQL在隐式转换时的varchar转double,会出现很多意想不到的情况,比如 “123”," 123","123a"都会转成123,实际场景中都是不允许出现的。

总结

  好了,MySQL的隐式转换就说到这,点到为止,这也是我最近突然自测出的bug,我们公司测试竟然毫不知情!真是为它感到羞愧~~ 真没想到会有这个坑,希望这篇文章你让你能避免它!

  一个野鸡大学非科班程序员,北漂五年,还有梦想,依旧很远。一起,加油兄弟们!

附、一张有故事的照片(十七)

这是一位网友周末在家拍到的
其实,一个对所有人都很外向的人,也不一定是真的外向。
或许,对他来说,一个人在家才是最好的礼物。

令人炸毛儿的MySQL隐式转换 - 无形之刃,最为致命相关推荐

  1. mysql 隐式失误_评“MySQL 隐式转换引起的执行结果错误”

    今天看到一篇关于MySQL隐式转换引发执行结果错误的文章: ====================================================================== ...

  2. MySQL 隐式转换 字符串和整型说明

    MySQL 隐式转换 字段类型定义 CREATE TABLE `user` (`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '编号',/* ...... * ...

  3. mysql not in 转化_解析MySQL隐式转换问题

    一.问题描述 root@mysqldb 22:12: [xucl]> show create table t1G *************************** 1. row ***** ...

  4. mysql数据库隐式表_解析MySQL隐式转换问题

    一.问题描述 root@mysqldb 22:12: [xucl]> show create table t1\G *************************** 1. row **** ...

  5. mysql日期隐式转换_关于MySQL隐式转换

    一.如果表定义的是varchar字段,传入的是数字,则会发生隐式转换. 1.表DDL 2.传int的sql 3.传字符串的sql 仔细看下表结构,rid的字段类型: 而用户传入的是int,这里会有一个 ...

  6. mysql隐式转换造成索引失效的事故总结

    隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 由于表的字段tu_mdn定义为varchar2(20),但在查询时把该字段作为number类型以where条件传给mysql,这样 ...

  7. mysql 隐式转换 索引_MySQL性能优化:MySQL中的隐式转换造成的索引失效

    数据库优化是一个任重而道远的任务,想要做优化必须深入理解数据库的各种特性.在开发过程中我们经常会遇到一些原因很简单但造成的后果却很严重的疑难杂症,这类问题往往还不容易定位,排查费时费力最后发现是一个很 ...

  8. mysql 隐式转换 索引_MySQL SQL优化之字符串索引隐式转换

    之前有用户很不解:SQL语句非常简单,就是select * from test_1 where user_id=1 这种类型,而且user_id上已经建立索引了,怎么还是查询很慢? test_1的表结 ...

  9. MySql 隐式转换

    隐式转换主要发生在查询数字类型是出现.如把查询money=11写成age='11',tel="13323533013"写成tel=13323533013; 影响: 先贴个表结构: ...

最新文章

  1. Android热更新实现方式
  2. 加强数据中心安全的六条措施
  3. 第二阶段_第二小节_C#调试
  4. python print换行_Python中九九乘法表与古诗对话机器人及sep-end值
  5. 根据屏幕大小加载css,css根据屏幕大小切换样式
  6. SpringSecurityFilterChain
  7. mysql扩展中如何处理结果集_请写出PHP处理结果集的5个函数(使用mysql扩展)_学小易找答案...
  8. Spark学习记录(二)Spark集群搭建
  9. 大数计算器c语言实训报告,C语言计算器设计实验报告.doc
  10. Windows 使用命令行查看 wifi 密码
  11. ACM/ICPC 大赛常见英语词汇
  12. matlab 动态优化,基于Matlab的测控系统动态性能优化与仿真
  13. 嵌入式开发板如何自动登陆校园网实现上网
  14. SPSS多元线性回归输出结果的详细解释
  15. 什么样的人才是幸福的?
  16. Nature综述 | Rob Knight手把手教你分析菌群数据(全文翻译1.8万字)
  17. Android 动画应用大集合
  18. python企业微信群聊_给企业微信加个群机器人
  19. FPGA 视频拼接器的输入卡
  20. 服务器右键文件夹不显示共享,server2012共享文件夹、局域网共享设置权限的方法...

热门文章

  1. RuntimeError: expected scalar type Double but found Float
  2. The Biggest Water Problem
  3. 对全职高手的自然语言处理
  4. 华为荣耀3x G750-T01 Root操作
  5. WordPress 和继承者们
  6. C语言中怎么表示派 -π
  7. 个人日记-电影《夏日友晴天》观后感-2021-08-25
  8. iTOP-RK3568开发板Ubuntu系统修改dns
  9. BananaPi Wifi 连接
  10. MyBatis07:使用注解开发