目录
二次注入漏洞是Web应用程序中一种较为隐蔽且危险的安全漏洞形式。它与一次注入漏洞相比,虽攻击原理相似,但更难被发现。
一、二次注入漏洞概述
定义
二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到SQL查询语句中导致的注入。可能单次的输入处理不构成漏洞,但结合起来就可能引发注入问题。
存在原因
- 信任问题
- 开发者往往对直接来自用户的数据不信任,会进行转义后存储。然而,对于已存储的数据却过于信任,未经过滤、转义就放入SQL语句中,从而导致注入。
- 对函数理解不足
- 例如在PHP中,对一些函数如
is_numeric
理解不够准确。对于用户直接输入的内容,开发者有安全意识会做转义处理,但对于从数据库取出的数据,安全意识降低,而这些数据可能是用户间接输入的,从而引发漏洞。
- 例如在PHP中,对一些函数如
二、二次注入漏洞的危害
二次注入的危害等同于SQL注入的危害,包括但不限于数据泄露、数据库篡改、执行恶意SQL命令等。由于其隐蔽性好,不易被发现,所以比普通SQL注入更危险,虽然其存在数量通常少于直接的SQL注入。
三、二次注入漏洞与普通注入漏洞的区别
- 输入数据流向
- 普通注入数据直接进入到SQL查询中,而二次注入则是输入数据经处理后存储,取出后再次进入到SQL查询。
- 利用难度
- 二次注入比普通SQL注入利用更加困难,利用门槛更高。在渗透过程中,流程越复杂,不确定因素越多,成功率越低。例如,如果第二次注入必须由管理员在后台来被动触发,条件就很苛刻。
四、攻击者视角
挖掘思路
- 人工挖掘
- 由于二次注入漏洞的特性,自动化扫描很难发现,基本靠人工。挖掘时需要细心和耐心,回溯数据输入时不应忽略来自数据库、文件等的输入,要追溯其初始来源,判断是否可控。例如,要关注一些敏感函数如
is_numeric
是否存在误用情况。
- 由于二次注入漏洞的特性,自动化扫描很难发现,基本靠人工。挖掘时需要细心和耐心,回溯数据输入时不应忽略来自数据库、文件等的输入,要追溯其初始来源,判断是否可控。例如,要关注一些敏感函数如
- 代码审计
- 习惯在查询函数上设置断点或添加日志,然后在回溯代码过程中观察日志,寻找可能的注入点。
测试方法
- 在黑盒测试中,如果是报错注入且能爆出SQL语句,可以通过HTTP响应寻找蛛丝马迹。但一般很难通过普通的黑盒扫描找出二次注入漏洞。
- 在白盒测试中,如果有源码,可以倒着看代码,先看是否有拼接,输入点是否入库,还要多关注写入到数据库、文件、缓存中的内容。可以分析哪些数据库的列是可控的,以减少影响因素。
五、防御者视角
防御措施
- 预处理 + 数据绑定
- 这是解决SQL注入问题最推荐的方法,同样适用于二次注入漏洞的防御。
- 统一过滤转义
- 对输入一视同仁,无论输入来自用户还是存储,在进入到SQL查询前都对其进行过滤、转义。
代码规范
- 在做代码审查时,禁止开发用拼接的方式执行SQL,以减少二次注入漏洞的产生。
六、二次注入漏洞检测
检测工具
- 目前专门针对二次注入的自动化检测工具较少。开源工具中,如RIPS的下一代版本可能会支持二次注入检测(2014年有相关文章提及),还有Skywolf也可以检测但误报较高需优化。
检测流程
- 白盒检测
- 最好倒着看代码,先看是否有拼接,输入点是否入库,多关注写入数据库、文件、缓存中的内容。例如,在Java代码中,可以查看是否存在类似以下拼接SQL的情况(以下是错误示范):
String sql = "SELECT * FROM users WHERE username = '" + usernameFromDB + "' AND password = '" + passwordFromDB + "'";
- 正确的做法应该是使用预处理语句,如下:
String sql = "SELECT * FROM users WHERE username =? AND password =?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1, usernameFromDB);
ps.setString(2, passwordFromDB);
- 黑盒检测
- 主要是输入一些标记内容,然后通过观察和分析来判断是否存在二次注入漏洞。
通过了解二次注入漏洞的原理、攻防思路以及检测方法,开发人员和安全人员可以更好地保护Web应用程序免受此类漏洞的侵害。