现在网络安全越来越受到重视,后端应用中最常见的安全漏洞就是SQL注入,根据owasp(OpenWebApplicationSecurity)的安全漏洞统计项目组织),注入漏洞常年排名TOP3。为了尽可能减少SQL注入问题,我们总结了一些做法,并在部门内推广。SQL注入原理SQL注入攻击是通过操纵输入来修改SQL语句,从而执行注入的SQL,进而攻击Web服务器。简单地说,就是在Web表单或页面请求的查询字符串中插入SQL命令,最终使Web服务器执行恶意命令的过程。可以用一个例子来简单说明SQL注入攻击。假设显示一个网站页面时,URL为http://www.example.com?test=123。这个时候URL实际上是把值为123的变量test传给了服务器,这说明当前页面是动态查询数据库的结果。如果服务器使用SQL动态拼接,此时可以在URL中插入恶意SQL语句并执行。例如,预期的执行语句为:select*fromuserwheretestId=123如果有人恶意构造test=123or1=1;那么最终实际执行的语句是:select*fromuserwheretestId=123or1=1SQL注入的本质是利用DynamicSQL直接拼接执行,前端输入的参数直接参与未经严格校验的SQL拼接。如果输入参数被恶意使用,则存在不受控制的命令注入的风险。SQL注入会攻击数据库,所以危害非常严重。SQL注入的危害包括:1、数据库信息泄露;2、恶意操作数据库攻击服务器;3、数据库表信息的删除、修改;4、远程控制服务器等防SQL注入原理根据SQL注入的原理,我们总结出以下防止SQL注入的原则。1)尽可能参数化地执行SQ??L,使用PreparedStatement;2)如果参数化执行不能执行,对入参使用强类型接收,比如枚举;3)如果参数化和强类型都做不了,就要做格式校验;4)如果以上都做不了,最后考虑注入字符的转义过滤。防SQL注入实践总结实践一:使用数据库预编译SQL执行关系型数据库提供了一种预编译执行SQL语句的方式,区别于直接通过参数拼接执行SQL。在SQL预编译阶段,所有的参数都会被模板化,参数值不直接参与编译,这样参数值不能改变SQL结构,包括语句条数、参数个数、查询条件等,即使参数中存在恶意注入参数值,也无法破坏原有的SQL结构。以下示例说明了级联执行和参数化执行之间的区别。直接执行:selectnamefromuser_infowherename='gouge'使用预编译执行(即PreparedStatement)分两步执行。第1步:模板编译selectnamefromuser_infowherename=?第二步:将参数带入selectnamefromuser_infowherename='gouge'执行预编译语句时,即使参数值中存在恶意注入,也只会作为字符串的一部分,不会导致SQL结构被破坏,所以这种方法可以从根本上杜绝SQL注入的风险,是目前公认的最好的防止SQL注入的方法。做法二:可选地,先使用非String类型作为输入参数。SQL注入依赖于SQL动态拼接。如果非String(包括枚举)参数有强类型严格校验,则拼接时不存在SQL注入风险。实践三:对String类型参数进行枚举校验对于可枚举的String入参,需要在后端进行枚举值白名单校验,以防伪造。以经常使用的排序字段为例。很多时候,排序字段是前端传过来的,不可信。所以需要做枚举校验,看传入的排序字段是否在预期之内。实践4:存储过程存储过程也可以防止SQL注入,因为它们也是预编译的。但是,不建议使用存储过程。这里只是几个例子。实践5:转义字符串输入参数是此实用解决方案的最低优先级。只有在前面的方案无法实施或者成本太高的时候才会考虑,因为这种方法并不完全可靠。该方法是在将用户输入放入SQL之前对输入进行转义,所以实现是绑定数据库的,不同的数据库转义实现不同。原理是对于一个特定的查询,数据库支持一种或多种转义方式。如果所有用户输入的参数在拼写成SQL之前都进行了适当的转义,则可以防止SQL注入,但不能保证所有情况都可以处理。完美的。OWASP组织提供了可以直接使用的Java类库esapi,可以用来完成转义。目前支持mysql、oracle,不支持sqlserver。OWASP官方文档也声明这个类库不能保证100%防止SQL注入。Mybatis防止SQL注入。MybatisXMLMapper中参数的表达方式有两种:#{xxx}和${xxx}。不同的是#{xxx}会被模板化为参数化形式(?),所以参数值不参与编译;${xxx}会被替换成对应的参数值参与编译。所以使用#{xxx}语法的参数是没有注入风险的,但是${xxx}使用不当就会有注入风险。我们使用sonar规则检测${xxx}的使用,发现很多情况下#{xxx}可以使用,但是却使用了${xxx},可能是用户不理解其中的区别和风险。根据防止SQL注入的原则,在使用Mybatis作为ORM时,我们可以得出结论,在xml中,可以使用带参数的#{}语法,而禁止使用${},必须使用${}语法被用作最后的手段。使用SQL时,首先要进行合法校验和转义Mybatis-XML常见误用和安全建议1)常规误用风险写法:account='${account}'安全写法:account=#{account}2)inparameters拼接风险写作:WHEREidIN(${item.ids})安全写作:
