令人炸毛儿的MySQL隐式转换 – 无形之刃,最为致命

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

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

小伙伴想精准查找自己想看的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语句中隐式转换的坑

先看一下官方的隐试转换说明:
在这里插入图片描述

翻译成人话:

  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,我们公司测试竟然毫不知情!真是为它感到羞愧~~ 真没想到会有这个坑,希望这篇文章你让你能避免它!

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

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

在这里插入图片描述

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183071.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • web大前端必备的VSCode插件,常用的(15个)「建议收藏」

    web大前端必备的VSCode插件,常用的(15个)「建议收藏」VisualStudioCode是由微软开发的一款免费、跨平台的文本编辑器。由于其卓越的性能和丰富的功能,它很快就受到了大家的喜爱。就像大多数IDE一样,VSCode也有一个扩展和主题市场,包含了数以千计质量不同的插件。为了帮助大家挑选出值得下载的插件,我们针对性的收集了一些实用、有趣的插件与大家分享。1.Open-In-Browser由于VSCode没有提供直接在浏览…

    2022年7月25日
    42
  • windows下面安装Python和pip终极教程「建议收藏」

    windows下面安装Python和pip终极教程「建议收藏」在大二的时候接触过一段时间的Python,最近又开始玩起了这门语言。总的来说,个人很喜欢Python的语言风格,但是这门语言对于windows并不算很友好,因为如果是初学者在windows环境下安装,

    2022年7月5日
    24
  • java map遍历的几种方式_二叉树的三种遍历方式

    java map遍历的几种方式_二叉树的三种遍历方式一:在for循环中使用entries实现Map的遍历:二:在for循环中遍历key或者values,一般适用于只需要map中的key或者value时使用,在性能上比使用entrySet较好;三:通过Iterator遍历;

    2022年9月21日
    3
  • Apache的安装_Ubuntu安装Apache

    Apache的安装_Ubuntu安装Apache(一)apache介绍  ApacheHTTPServer(简称Apache)是Apache软件基金会的一个开放源码的网页服务器,Apache也叫万维网,www服务器, web服务器主要功能是提供网上信息浏览服务。Apache可以在大多数计算机操作系统中运行,由于其多平台和安全性被广泛使用,是最流行的Web服务器端软件之一。     目前主流的Web服务器软件包括:Apache,Ngi…

    2025年11月13日
    4
  • 中缀表达式转后缀表达式栈的变化_利用栈实现中缀转后缀

    中缀表达式转后缀表达式栈的变化_利用栈实现中缀转后缀这里给出中缀表达式转后缀表达式的算法过程,以及再举两个例子算法过程:1.数字直接加入后缀表达式2.如果是‘(’,入栈3.如果是‘)’,则依次把栈中的运算符加入后缀表达式,直到出现‘(’并从栈中删除它4.如果是运算符+-*/a.栈空或者栈顶元素为‘(’,入栈b.高于栈顶元素优先级,入栈c.否则依次弹出栈顶运算符,直到遇到一个优先级小于它的运算符或者是遇到‘(’为止5.遍历完成后,如果栈非空则依次弹出所有栈顶元素加入到表达式当中例1:…

    2025年6月24日
    4
  • vue-router(路由)详细教程

    vue-router(路由)详细教程  由于Vue在开发时对路由支持的不足,于是官方补充了vue-router插件。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,实际上就是组件的切换。路由就是SPA(单页应用)的路径管理器。再通俗的说,vue-router就是我们WebApp的链…

    2022年7月11日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号