网站建设的基本流程可分为,织梦视频资讯网站源码,北京互联网公司大厂有哪些,环保网站建设项目备案系统我相信90%以上的同学们在平时开发时#xff0c;或多或少都被隐式转换#xff08;CONVERT_IMPLICIT#xff09;坑过#xff0c;甚至测出bug前你都浑然不知。你还别不信#xff0c;“无形之刃#xff0c;最为致命#xff01;” mysql SELECT * from t_user;
---------… 我相信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 password1234;感觉没有明显的毛病来看看结果mysql SELECT * from t_user where password1234;
-------------------------
| id | username | password |
-------------------------
| 2 | 侨布斯 | 1234 |
| 3 | 提莫 | 1234abcd |
-------------------------
2 rows in set, 1 warning (0.00 sec)???这怎么把提莫队长给打现行了
好了其实这算是MySQL给开发者留下的不友好的礼物坑。今天我们一起从以下三个角度去聊一聊MySQL的隐式转换。
索引 1、SQL语句中隐式转换的坑
先看一下官方的隐试转换说明
翻译成人话
两个参数至少有一个是 NULL 时比较的结果也是 NULL例外是使用 对两个 NULL 做比较时会返回 1这两种情况都不需要做类型转换。两个参数都是字符串会按照字符串来比较不做类型转换两个参数都是整数按照整数来比较不做类型转换十六进制的值和非数字做比较时会被当做二进制串有一个参数是 TIMESTAMP 或 DATETIME并且另外一个参数是常量常量会被转换为 timestamp有一个参数是 decimal 类型如果另外一个参数是 decimal 或者整数会将整数转换为 decimal 后进行比较如果另外一个参数是浮点数则会把 decimal 转换为浮点数进行比较所有其他情况下两个参数都会被转换为浮点数再进行比较。这里所说的浮点数一般默认为double类型可以看到非前六种以外的类型转换都要转成浮点类型来处理这意味着什么意味着MySQL承认了隐式转换这个事儿还表示不爱看官方文档的哥们儿出问题活该~~ 我们用一些具体示例来看一下通过下述SQL可见当1234没有引号也就是整数时‘1234abcd’ 1234 → true说明MySQL对’1234abcd’做了转型转成了浮点类型结果是1234abcd 1234 # 0false1true
mysql SELECT 1234abcd 1234;
---------------------
| 1234abcd 1234 |
---------------------
| 0 |
---------------------
1 row in set (0.00 sec)# 0false1true
mysql SELECT 1234abcd 1234;
-------------------
| 1234abcd 1234 |
-------------------
| 1 |
-------------------
1 row in set, 1 warning (0.00 sec)为啥1234abcd 1234呢 其实’1234’和’abcd’都会转成浮点数即123401234非数字类型的都被直接转成了 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得a11111 → 0 mysql SELECT * from t_user where password1234;
-------------------------
| 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 password0;
-------------------------
| 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 11 那么password是啥都无所谓了是吧。 懂我意思吧快改了。 当然其实很多注入攻击的真实目的并不是用来破解用户账号的而是破坏服务器。一般我们在页面F12发现有问题的接口后通过脚本模拟请求参数构造注入参数去不断尝试自定义构造limit、order、where等条件或许花不了多久就能通过一个不规范的请求入口检索出该表甚至其他大表全量信息。导致公司服务器负载异常连接数打满CPU200%等有趣的情况。有兴趣的同学可以花几小时尝试破解自己公司的web~~
3、索引中隐式转换的坑 同理在MySQL根据索引进行查询时如果你的username字段有索引且为varchar类型且查询如下时 select * from t_user where username123;该SQL会出现两个问题
1、索引失效 无法使用到索引查询因为mysql会在引擎层进行类型隐式转换CONVERT_IMPLICIT会先把username隐式转换成浮点数然后再跟你的123进行比较然而你的索引是建在username上的并不是在转换后的username上的所以进行转换后的username相当于没有索引。会全表扫描换做大表中无法使用索引你懂得。
2、查询结果不准确 第一部分我们已经举例说明MySQL在隐式转换时的varchar转double会出现很多意想不到的情况比如 “123” 123123a都会转成123实际场景中都是不允许出现的。
总结
就是当sql中一个字符串和一个数字做、、-、/ 计算时,如a1bc1, ccccd30
这个字符串中的非数字的字符会被隐式转换成0并且再转换为空,再去做比较.只分以下两种情况:
1.前面的字符不是数字时,直接等于0,如a10,abcd10
2.前面的字符是数字时,从第一个开始截取,从左往右直到出现的第一个不是数字的字符为止,截取的字符串就是最终转换的值,如1a1,2a3b2,55555h66666655555