SQL注入攻击与防护(进阶篇)
字数 1061 2025-11-24 04:42:30
SQL注入攻击与防护(进阶篇)
描述
SQL注入是一种将恶意SQL代码插入到应用程序输入参数中,从而操纵后端数据库的攻击技术。进阶篇将深入探讨盲注、时间盲注、堆叠查询等复杂技术,以及ORM注入、二次注入等现代变种。
解题过程
-
SQL注入原理回顾
- 根本原因:用户输入被直接拼接到SQL查询语句中,且未经过滤或转义。
- 示例:
SELECT * FROM users WHERE username = '${input}',若输入admin' OR '1'='1,查询变为永真条件。
-
进阶注入技术分类
- 盲注(Blind SQLi):
- 场景:页面不返回具体数据,但根据查询真假显示不同行为(如“存在/不存在”)。
- 方法:通过布尔逻辑(如
AND 1=1/AND 1=2)或条件触发延迟(时间盲注)逐字符提取数据。
- 堆叠查询(Stacked Queries):
- 场景:支持多条SQL语句执行(如MySQL的
mysqli_multi_query)。 - 风险:攻击者可插入
; DROP TABLE users等破坏性语句。
- 场景:支持多条SQL语句执行(如MySQL的
- ORM注入:
- 成因:误用ORM(如Hibernate)的原始查询或不当参数绑定,例如HQL中
WHERE name = '${input}'仍可被注入。
- 成因:误用ORM(如Hibernate)的原始查询或不当参数绑定,例如HQL中
- 二次注入:
- 流程:恶意输入先被存入数据库,后续从数据库取出时被拼接到查询中,绕过初次过滤。
- 盲注(Blind SQLi):
-
防护机制深度剖析
- 参数化查询(核心防御):
- 原理:将输入作为参数传递而非拼接,数据库区分代码与数据。
- 示例:
-- 错误方式 query = "SELECT * FROM users WHERE id = " + userInput; -- 正确方式(使用占位符) query = "SELECT * FROM users WHERE id = ?"; preparedStatement.setInt(1, userInput);
- 输入验证与白名单:
- 对数字参数校验范围,对字符串使用正则表达式限制字符集(如仅允许字母数字)。
- 最小权限原则:
- 数据库账户仅授予必要权限(如禁止执行
DROP、FILE操作)。
- 数据库账户仅授予必要权限(如禁止执行
- ORM安全实践:
- 避免拼接HQL/JPQL,使用命名参数(如Hibernate的
setParameter方法)。
- 避免拼接HQL/JPQL,使用命名参数(如Hibernate的
- 参数化查询(核心防御):
-
实战案例:时间盲注检测
- 步骤:
- 判断注入点:输入
id=1' AND SLEEP(5)--,观察响应是否延迟。 - 逐字符提取数据:
id=1' AND IF(SUBSTR(database(),1,1)='a', SLEEP(5), 0)-- - 自动化工具:使用Sqlmap的
--time-sec参数指定延迟时间。
- 判断注入点:输入
- 步骤:
-
现代框架中的陷阱
- 即使使用ORM,以下情况仍可能失效:
- 动态表名/列名拼接(如
"SELECT * FROM " + tableName)。 - 原生SQL片段未参数化(如JPA的
@Query中拼接字符串)。
- 动态表名/列名拼接(如
- 即使使用ORM,以下情况仍可能失效:
通过结合严格编码规范、工具扫描(如SAST/DAST)和纵深防御,可系统性规避SQL注入风险。