本文转载自微信公众号“小姐姐的味道”,作者小姐姐养的狗。转载本文请联系味觉小姐公众号。一直以来,我认为后端开发在安全方面最容易出问题的就是SQL注入。通过where1=1这种神奇的SQL写法,很容易对有问题的系统进行攻击,从而最终进化出sqlmap这样的神器。后来fastjson刷新了我的认知,这个框架也算是对互联网安全概念的一种推广。连不懂技术的老板都知道fastjson速度快,而且作为程序员,安全观念也提升了一次。为什么对sql注入情有独钟?因为开发者和SQL打交道的地方太多了。甚至有些专门做报表开发的同学,写的SQL行比代码行还多!问题是。很久很久以前,早在10年前就有人喊SQL注入已死,但时至今日,仍然有大量的SQL注入教程和SQL注入案例。毫不夸张地说,SQL注入是漏洞之王。当然,在这方面,PHP的贡献最大,Java是远远落后的。SQL注入之所以流行,是因为开发者对自己太过自信,或者是他们使用的工具太原始,没有经过框架层的过滤。如果你在Java世界中使用MyBatis或者JPA,SQL注入的可能性就变得很低了。现在PHP也有了类似thinkphp的框架,也就是说可以利用的SQL注入漏洞越来越少了。但这并不意味着没有,只是门槛提高了。下面以MyBatis为例,看看是否还会出现SQL注入。MyBatis还是有SQL注入的。使用Mybatis的同学,最先接触到的概念就是#和$的区别。这两个符号和Shell中的魔法符号很像,幸好只有两种情况。#表示使用sql预编译,安全可靠$表示使用concatenation,存在SQL注入风险。比如下面的xml配置,就是一种绝对安全的写法。因为整个#{id}都会被替换成?。SELECT*FROMorderWHEREid=#{id}但不幸的是,在某些场景下,预编译的方式是无法使用的(或者你就是不知道或者偷懒)。像一些代码重构,动态传入表名/列名/排序等字段时,难免需要进行SQL拼接,SQL注入还是有头有脸的。但是比较容易出问题的是LIKE、IN等类似的语句。下面是两个Like模糊查询的写法。实际测试会发现用#不好用,会报错,需要用$做sql拼接。问题由此产生。SELECT*FROMorderWHEREnamelike'%#{name}%'//会报语法错误SELECT*FROMorderWHEREnamelike'%${name}%'//可以运行,正确的写法应该是函数拼接。但是工期压死人,不知不觉中,大部分人都选择了简单的写法。毕竟功能是第一位的,也是体现工作量最重要的方式。SELECT*FROMorderWHEREnamelikeconcat('%',#{name},'%')//正确的写法IN语句也存在同样的问题。in(#{tag})//报错in(${tag})//可以运行。既然几个字就可以运行,当然没有人会选择下面这种复杂的写法。tagin#{tag}和orderby,不要掉以轻心,一不小心就会万劫不复。SELECT*FROMorderorderbycreateDate#{sortType}//报错SELECT*FROMorderorderbycreateDate${sortType}//此时需要将sortType加入白名单。不就是ASC和DESC吗,你传给我一个长字符串有什么关系?综上所述,2021年SQL注入依然存在,只是门槛提高了。SQL注入的减少现在是框架的原因,和程序员的水平无关。sql拼接的情况永远不会消失,因为它是最快最简单的方式,而且会让人上瘾。数不清的外包项目和系统已经死了十多年。希望在框架层杜绝所有的SQL注入是梦想。因为它的对手是人性的懒惰。没有人能打败它。