当前位置: 首页 > 科技观察

经销商技术部-防SQL注入实践

时间:2023-03-18 17:53:25 科技观察

现在网络安全越来越受到重视,后端应用中最常见的安全漏洞就是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})安全写作:0">ANDIN#{id}3)sqlservertop语法风险写法:top${queryCnt}安全写法:top(#{queryCnt})4)语法风险写作之间:BETWEEN${start}AND${end}安全写作:BETWEEN#{start}AND#{end}5)语法风险写作:emaillike'%${emailSuffix}'安全写作方法1:emaillikeconcat('%',#{emailSuffix})安全写法2:Emaillike#{pattern}安全写法3:在java中code中间构造好pattern,使用#{}语法6)limit语法风险写法:limit${offset},${size}safewriting方法:limit#{offset},#{size}7)动态orderby风险写法:orderby${orderByClause}安全建议1:可以在xml中使用if而不是在java中patchorderby(推荐);安全建议2:正确排序字段的白名单验证和排序类型值;8)动态表名安全建议:建议实现Mybatis插件,在框架层面替换表名,避免在xml中使用${}拼凑表名9)Mybatisexample语法风险用法:orderby${orderByClause}Mybatis生成的example大部分情况下是安全的,但是orderByCluase是通过字符串拼接的,同样不安全,所以它的使用不受到推崇的。安全建议:可以考虑使用mybatis新增的mybatis-dynamic-sql或者国内开源的mybatis-plus,比示例语法更加简洁安全。例如:Query.orderBy(createAt.descending());除了在SQL语句层面防范SQL注入风险,基础设施中的WAF(WebApplicationFirewall)也是防范SQL注入的非常有效的措施。考虑部署WAF。小结本文主要记录了经销商技术部门在安全方面防范SQL注入的一些实践探索和总结,包括SQL注入的原理、防范SQL注入的一般原则以及实践中具体的安全建议。我希望它会对其他人有所帮助。也有帮助。