自从有了OWASP TOP的排名依赖,注入问题就一直排名前三,这就说明了注入问题对系统的影响是十分严重的,而且,注入问题一般比较容易被利用。
注入问题产生的根本原因就是程序在接受到请求中的参数时,没有经过严格的验证和正确地使用就直接被使用于解释型语言、结构化查询语言或者标签语言等语言的环境里用作程序执行的一部分。它的发生需要两个条件:1) 数据来源可以被攻击者控制和篡改;2)数据被用做解释性语言、结构化查询语言或者标签语言的一部分。以SQL注入为例,它是结构化的查询语言,当由用户输入作为SQL语句的一部分时,就会产生SQL注入。
了解了注入发生的根本原因之后,关于预防就相对来说比较容易理解了。根据它发生的两个条件,来探索实施方案。第二个条件一般是无法避免的,那就只有解决第一个条件。第一个条件是“数据来源可以被攻击者控制和篡改”,预防方法有:输入验证、特殊字符转义、编码、输出净化以及使用安全的框架或者安全的API。下面逐一介绍它们。
输入验证
这是最常用的注入预防措施之一,也是相对而言最简单和直接的方法。但是,也是最容易犯错误的一种方法。
错误一:使用黑名单过滤,开发根据自己的理解列出一个黑名单,根据黑名单来验证,对于一些有明确的黑名单列表的漏洞类型,这种方法比较有效;但是,对于一些比较负责的漏洞类型,例如:XSS,可能就比较麻烦。而且,随着技术的发展,黑名单也可能出现变动,例如:有新的HTML标签出现等。在一些情况下,当黑名单字符是合理输入的一部分,这种方法就会彻底失效,例如,SQL禁止输入单引号(‘),但是有些国家或者地区的人名中就含有单引号,例如:O’neal,这整情况就无法限制用户不能输入黑名单中的字符。
错误二:搜索输入的字符串中含有危险字符串直接替换成空,这种做法看似很完美,但是,漏洞百出。我在漏洞修复的Review中,经常发现修复路径遍历漏洞的源代码是把../替换成空,但是当输入中含有:.../.../时,把../替换成空的结果还是../。所以,再任何时候尝试去修复错误是一件非常危险的做法。
特殊字符转义
针对一些执行环境中的语言的一些特殊字符,相对应的库一般都会提供相应的API对特殊字符进行转义处理,例如:mysql_escape_string,他的核心原理就是使用反斜杠\针对特殊字符进行处理,例如,' 被处理成 \',SQL解析器针对他处理时,会把反斜杠理解为一种个数字符将\’解析为单引号字符,而不是字符串的开头或者结尾,这样就避免了通过单引号注入额外的内容。针对这种处理,apache common lib提供了一个类,用于处理各种情况的转义,具体的API信息可以参考:https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringEscapeUtils.html。
编码
根据编码的定义:编码是信息从一种形式或格式转换为另一种形式的过程,也称为计算机编程语言的代码简称编码。用预先规定的方法将文字、数字或其它对象编成数码,或将信息、数据转换成规定的电脉冲信号。编码在电子计算机、电视、遥控和通讯等方面广泛使用。编码是信息从一种形式或格式转换为另一种形式的过程。解码,是编码的逆过程。
可以知道,编码就是将信息转换成另外一种形式,而且可以通过解码还原。常用的编码方式有:base64,16进制编码等。
常用到编码的方式的漏洞类型是:XSS和HPP。关于XSS常用的就是HTML编码,将特殊字符<>’”/等以HTML编码的形式输出,浏览器在显示时,会自动进行解码,这样特殊字符就可以显示为原始字符,而不用担心特殊字符会影响原始背景的显示问题。编码一般都在输出的地方使用。也就是说,当输出时可能产生注入问题时,首先要考虑是否有编码方案来保证输出的准确性。
常见的HTML字符和编码方式如下:
关于HPP一般都建议使用URL编码来处理,关于URL编码,可以参考:https://docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html
输出净化
输出净化主要是当输出不能适用编码方案时的解决方案。当输出的是富文本框时,由于输出的本身就是HTML,这是使用编码就会导致显示不正确。需要根据使用的HTML标签列表,设置一个白名单,但一个标签不在白名单中时,直接将其净化处理,来避免可能的注入问题。
关于HTML的处理,可以参考OWASP ANTISamy或者https://github.com/OWASP/java-html-sanitizer。
使用安全架构或者安全API
有些语言针对某些情况提供了一些安全架构或者安全API,采用这些安全的架构或者API,就可以有效避免一些注入问题。例如,Java的PrepareSatement类;Java的iBatis或者JPA都提供了方法来避免SQL注入漏洞的产生。不过,在使用这些框架或者API,也需要注意一点:不要自己组装SQL,一旦,使用自组装的SQL,任何框架或者API,都解决不了注入的问题。同时,使用框架时,有时为了灵活性,也提供了一些不安全的方式,这是就需要注意在使用时需要了解哪些方式是安全的,哪些方式是不安全的。例如:MyBatis,参数使用#时系统会安全处理,参数使用$时,就会有风险。总之,使用第三方的框架或者库时,一定要了解清楚用法,才可以避免不必要的注入问题。
关于各种注入的特殊字符和建议处理方案可以参考https://blog.csdn.net/jimmyleeee/article/details/107210402
关于注入问题的处理的时机和方案,最后总结如下:
各种注入类型和产生的时机如下表: