二阶注入(Second-Order Injection)是一种特殊的 SQL 注入攻击,通常发生在用户输入的数据首先被存储在数据库中,然后在后续的操作中被使用时,触发了注入漏洞。与传统的 SQL 注入(直接注入)不同,二阶注入并不会立即触发,而是需要等到数据再次被调用时才会执行。
二阶注入的工作原理
- 注入数据存储:攻击者将恶意的 SQL 注入代码作为普通数据输入存入数据库。由于在存储阶段数据库对输入数据进行了转义,直接注入的攻击无法生效。
- 二次调用触发:在某些情况下,应用程序会调用数据库中存储的数据,并将其拼接到另一条 SQL查询中执行。此时,原先存储的恶意代码将被解析,从而引发 SQL 注入。
示例:sqlilabs-less24(POST-Second Oder Injections Real treat-Stored Injections)
- 注册特殊用户:
访问注册页面,创建一个用户名为 admin’# 的用户,密码可设为任意值。
此时,数据库中会存储该用户名。
- 登录并修改密码:
使用刚才注册的用户 admin’# 登录系统。
登录成功后,进入修改密码页面。
在新密码字段中输入新的密码,提交修改请求。
- 分析 SQL 语句:
在修改密码的过程中,应用程序可能执行如下 SQL 语句:
UPDATE users SET password='new_password' WHERE username='admin'#' AND password='current_password';
由于 # 在 SQL 中表示注释符号,实际执行的语句变为:
UPDATE users SET password='new_password' WHERE username='admin';
这意味着,数据库中用户名为 admin 的用户密码被修改为 new_password。
- 使用admin登录,验证成功:
使用用户名 admin 和新设置的密码登录系统,验证成功。
二阶注入的常见场景
- 用户信息存储:攻击者可以在注册时,在用户名或其他字段中插入恶意 SQL代码。之后,当管理员或系统在查询该用户数据时,恶意代码可能会执行。
- 应用日志记录:在记录日志时,存储了包含 SQL 注入代码的输入数据,可能在日志回溯或展示时引发 SQL 注入。
- 多步表单:有时用户提交的数据在多步骤的表单中传递,每一步都会使用数据库查询来验证或处理该数据。
防御二阶注入的建议
- 使用预处理语句:在所有 SQL 查询中使用预处理语句(Prepared Statements),避免直接拼接用户输入。
- 数据清理:在插入和读取数据时都进行严格的输入验证和转义,以确保不会执行恶意代码。
- 编码和解码:确保从数据库读取的数据没有被再次解码为 SQL 代码。
- 严格的权限控制:限制数据库用户的权限,确保即便存在 SQL 注入,攻击者的破坏性也受到限制。
总结
二阶注入相对隐蔽,因为其恶意代码不会在第一步直接执行,所以在开发和测试时,务必要考虑输入数据在不同阶段的调用方式,以避免此类攻击。