SQL注入之二次注入
字数 1194 2025-08-15 21:32:05
SQL二次注入攻击详解
一、二次注入原理
二次注入是一种特殊的SQL注入攻击形式,其核心原理如下:
- 数据存储阶段:攻击者向数据库存入恶意构造的数据(如包含SQL特殊字符的输入)
- 数据转义处理:在数据插入数据库时,应用程序会对输入进行转义处理(如使用
mysql_real_escape_string()函数) - 数据信任假设:应用程序默认数据库中存储的数据都是安全的,在后续查询使用时不再进行转义处理
- 恶意数据触发:当这些被存储的恶意数据被应用程序从数据库取出并用于构建新的SQL查询时,就会触发注入漏洞
与普通SQL注入相比,二次注入更难被发现,因为:
- 攻击发生在两个阶段(存储阶段和使用阶段)
- 常规安全扫描工具难以检测
- 攻击行为与正常操作流程相似
二、典型攻击场景分析
以SQL-Labs第24关为例,演示完整的二次注入攻击流程:
1. 注册恶意账号
攻击者注册一个特殊构造的用户名:
admin'#
- 单引号(
')用于破坏SQL语句结构 - 井号(
#)是MySQL注释符,用于注释掉后续语句
2. 修改密码操作
当攻击者登录后尝试修改密码时,后端执行的SQL语句:
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'";
由于$username从数据库直接取出未转义,实际执行的语句变为:
UPDATE users SET PASSWORD='newpass' where username='admin'#' and password='$curr_pass'
被注释掉的部分:
#' and password='$curr_pass'
最终有效执行的语句:
UPDATE users SET PASSWORD='newpass' where username='admin'
结果:admin用户的密码被修改,而非攻击者自己的账号
三、深入技术分析
1. 关键函数说明
mysql_real_escape_string()函数:
- 转义SQL语句中的特殊字符
- 影响的特殊字符:
\x00,\n,\r,\,',",\x1a - 仅在数据插入时有效,无法防止从数据库取出数据后的注入
2. 二次注入的利用方式
通过UNION查询获取敏感信息:
- 注册特殊构造的用户名:
1' union select 1,user(),database()#
- 当应用程序从数据库取出该用户名并用于查询时:
$sql_detail = "SELECT * FROM users where username='$username'";
实际执行:
SELECT * FROM users where username='1' union select 1,user(),database()#'
- 有效执行的查询:
SELECT * FROM users where username='1' union select 1,user(),database()
结果:泄露数据库用户和当前数据库名称
四、防御措施
-
输入验证:
- 对所有用户输入进行严格验证
- 使用白名单机制限制输入格式
-
参数化查询:
- 使用预处理语句(Prepared Statements)
- 确保查询结构与数据分离
-
输出转义:
- 即使数据来自数据库,在使用前也应进行转义
- 根据使用场景选择合适的转义函数(如HTML、SQL等)
-
最小权限原则:
- 数据库账户应仅具有必要的最小权限
- 避免使用高权限账户执行常规操作
-
代码审计:
- 检查所有从数据库取出数据后直接用于SQL查询的代码
- 特别注意用户可控数据的流动路径
五、总结
二次注入攻击利用了应用程序对数据库数据的过度信任,通过以下特点区别于传统注入:
- 攻击分两个阶段完成
- 恶意数据先被"合法"存储
- 漏洞触发时数据来源看似可信
- 防御需要关注整个数据处理生命周期
彻底防御二次注入需要开发者建立"永远不信任任何数据"的安全意识,无论数据来自用户输入还是数据库。