文章目录
-
- [一、PHP-MySQL 数据请求类型(决定"怎么拼 SQL")](#一、PHP-MySQL 数据请求类型(决定“怎么拼 SQL”))
-
- [1️⃣ 数字型(无符号干扰)](#1️⃣ 数字型(无符号干扰))
- [2️⃣ 字符型(有引号干扰)](#2️⃣ 字符型(有引号干扰))
- [3️⃣ 搜索型(多符号干扰)](#3️⃣ 搜索型(多符号干扰))
- [4️⃣ 框架型(括号 / 多层符号)](#4️⃣ 框架型(括号 / 多层符号))
- [二、PHP-MySQL 数据请求方法(决定"注入点在哪")](#二、PHP-MySQL 数据请求方法(决定“注入点在哪”))
-
- [1️⃣ 常见 PHP 数据来源(全局变量)](#1️⃣ 常见 PHP 数据来源(全局变量))
- [2️⃣ HTTP Header 注入点(重点)](#2️⃣ HTTP Header 注入点(重点))
-
- (1)User-Agent
- (2)Cookie
- (3)X-Forwarded-For(XFF)
- [(4)Referer / Host](#(4)Referer / Host)
- [3️⃣ 文件上传名 → INSERT 注入](#3️⃣ 文件上传名 → INSERT 注入)
- [三、PHP-MySQL 数据请求格式(决定"怎么传数据")](#三、PHP-MySQL 数据请求格式(决定“怎么传数据”))
-
- [1️⃣ JSON 格式传输](#1️⃣ JSON 格式传输)
- [2️⃣ 编码 / 加密传输(Base64 等)](#2️⃣ 编码 / 加密传输(Base64 等))
- 四、本节课的统一核心结论
- 五、与之前一致的「三步法」扩充总结(实战版)
本节课核心:
SQL 注入是否能成功,根本不取决于"有没有漏洞",而取决于"你是否拼对了原 SQL 语句"而黑盒测试中,原 SQL 语句是未知的 ,只能通过分析数据请求的类型、方法、格式去逼近真实语句。
一、PHP-MySQL 数据请求类型(决定"怎么拼 SQL")
数据请求类型 ≈ 原 SQL 中变量所在的位置与上下文
不同类型 → 需要不同的闭合方式与注入语法
1️⃣ 数字型(无符号干扰)
原 SQL 示例
select * from news where id=$id;
特点
$id未被引号包裹- 直接参与数值运算或条件判断
- 不需要闭合引号
注入特征
-
可直接拼接逻辑
?id=1 and 1=1
?id=1 union select ...
失败常见原因
- 实际是字符型,但误以为是数字型
- 后端做了强制类型转换(intval)
2️⃣ 字符型(有引号干扰)
原 SQL 示例
select * from news where id='$id';
特点
$id被 单引号或双引号包裹- 注入前必须闭合引号
注入特征
?id=1' and '1'='1
?id=1' union select ...
关键点
- 判断是
'还是" - 判断是否存在转义或过滤
3️⃣ 搜索型(多符号干扰)
原 SQL 示例
select * from news where id like '%$id%'
特点
- 前后存在
% - 实际上下文更复杂
- 注入点被夹在字符串中间
注入思路
-
先逃逸
%+' -
再重构逻辑
?id=%' and 1=1 and '%'='
实战难点
- 很多 payload 拼接失败并非无注入,而是上下文没对齐
4️⃣ 框架型(括号 / 多层符号)
原 SQL 示例
select * from news where id=('$id');
select * from news where (id='$id');
特点
- 框架或 ORM 自动加括号
- 实际 SQL 结构不直观
- 常见于 ThinkPHP / Laravel / 自封装框架
注入难点
- 需要额外考虑:
()- 引号
- 函数包裹
结论
框架型 ≠ 无注入
而是 拼接容错率更低
二、PHP-MySQL 数据请求方法(决定"注入点在哪")
凡是能进入数据库的地方,都是潜在注入点
1️⃣ 常见 PHP 数据来源(全局变量)
| 来源 | PHP 变量 |
|---|---|
| GET | $_GET |
| POST | $_POST |
| Cookie | $_COOKIE |
| Header | $_SERVER |
| 文件 | $_FILES |
2️⃣ HTTP Header 注入点(重点)
(1)User-Agent
用途
- 记录用户系统 / 浏览器
- 常被写入数据库用于统计
风险
insert into log(user_agent) values('$ua');
→ INSERT 型 SQL 注入
(2)Cookie
用途
- Session 跟踪
- 用户识别
特点
- 用户完全可控
- 经常被忽略过滤
(3)X-Forwarded-For(XFF)
用途
-
获取"真实 IP"
-
常见代码:
$_SERVER['HTTP_X_FORWARDED_FOR'];
典型注入场景
- 登录时记录 IP
- IP 白名单校验
- 防注入日志记录 IP
三种风险点
- 逻辑绕过:伪造固定 IP
- SELECT 注入:IP 参与白名单查询
- INSERT 注入:IP 写入数据库
(4)Referer / Host
特点
- 极少做过滤
- 在统计、日志、反爬中常入库
3️⃣ 文件上传名 → INSERT 注入
场景
$filename = $_FILES['file']['name'];
insert into upload(name) values('$filename');
风险
- 文件名可控
- 易被忽略
- 可配合报错 / 延时注入
三、PHP-MySQL 数据请求格式(决定"怎么传数据")
1️⃣ JSON 格式传输
特点
-
前端统一 JSON
-
后端解析后入库
{
"id": "1' and 1=1 -- "
}
风险
- 开发者误以为"不是表单就安全"
- 实际解析后仍是字符串拼接 SQL
2️⃣ 编码 / 加密传输(Base64 等)
流程
前端 → 编码/加密 → 后端解码 → SQL
关键点
- 注入 payload 是在"解码后"生效
- 需要先编码再测试
结论
编码 ≠ 防注入
只是增加了一层处理
四、本节课的统一核心结论
SQL 注入的本质不是"有没有过滤"
而是"你是否拼对了真实 SQL 语句"
黑盒失败 ≠ 无漏洞
很可能是:
- 数据类型判断错
- 符号上下文没闭合
- 注入点不是你测试的那个参数
五、与之前一致的「三步法」扩充总结(实战版)
你之前一直用的那套,这里只做"本课内容映射",不换框架
第一步:数据输入是否可控?
- GET / POST 参数
- Cookie
- Header(XFF / UA / Referer / Host)
- 文件名
- JSON 字段
- 编码前的原始数据
👉 可控 ≠ 可注入,但不可控一定无注入
第二步:数据输入后用到了哪里?
重点关注是否进入:
selectinsertupdatedelete- 日志 / IP 记录 / 统计表
👉 只要进了 SQL,就进入注入可能性分析阶段
第三步:能否改变逻辑或执行东西?
结合本课内容具体判断:
- 是数字型 / 字符型 / 搜索型 / 框架型?
- 是否需要闭合
' " ) % - 能否:
- 改 WHERE 条件
- UNION 查询
- 报错
- 延时
- 写入数据
一句话总结本课实战思想
不要问"有没有 SQL 注入"
而要问"这条 SQL 原本长什么样"
用"被动输入"去期待"主动判断能力"的出现