Week 3 收尾:一次完整的注入风险验证该怎么做、怎么记
网络安全实战 90 天 · Week 3 注入风险 | 难度 ★★★ 进阶 | 关键词:验证流程 只读判断 风险定级 修复建议 复现记录
这一周从原理讲到了绕过,最后要回答一个工程问题:给你一个接口,你按什么顺序查、查完怎么写、写的东西别人能不能照着复现。这篇是一次完整的走查记录,全程只读,目标是自己搭的靶场。
一、这一周到底在练什么
不是练 payload。payload 会过期,库版本一升就换写法。练的是判断链条:看到一个参数,能推出现在处在链条的哪一环、下一环需要什么证据、拿不到证据时该怎么记录。
| 阶段 | 要回答的问题 | 拿不到时怎么办 |
|---|---|---|
| 定位 | 哪个参数进了 SQL,怎么进的 | 读后端代码或看报错,不猜 |
| 确认 | 真假条件能不能区分 | 换观察量:条数 → 状态 → 耗时 |
| 摸结构 | 几列、哪几列有回显 | 用逐级收窄代替一次性取全 |
| 定量影响 | 能读到哪些数据、到哪一层 | 只记确实读到的,不外推 |
| 记录 | 别人能否照着复现 | 把请求、判据、结果写全 |
说明 本文所有操作均为自建靶场(本机容器中的 DVWA 与 SQLi-Labs)上的只读验证,用于练习判断与记录方法,不涉及任何真实业务系统。授权范围内的真实验证同样遵守「只读、最小影响」原则。
二、第一到第三步:定位、确认、摸结构
先找到一个确定会走数据库的查询入口,然后拿真假两个条件去撞,确认响应可区分。这一步一旦成立,后面的都是流水线。
bash
text
id=1 AND 1=1 # 返回正常列表
id=1 AND 1=2 # 返回空
两条响应不同,说明条件被代入执行了。接着确定结构:先数有几列,再确认哪几列的内容会被打回页面,然后才能把查询结果拼进去。
bash
text
id=1 UNION SELECT version(),database()
id=1 UNION SELECT user(),2
id=1 UNION SELECT schema_name,2 FROM information_schema.schemata
三条请求分别取到了数据库版本、当前库、数据库账号标识和库名列表。这些是「摸结构」阶段的产出,属于只读信息,不涉及任何业务数据。



三、第四步:定量,到哪一层就停
定量是定级的依据,也是最容易越界的地方。做法是先把范围收窄到一张表,确认能读到列名,再取一行样本说明字段含义------不需要、也不应该把整表拉下来。
| 验证层级 | 产出 | 是否必须 |
|---|---|---|
| 库名 | 确认目标库存在 | 必须 |
| 表名清单 | 确认业务表结构规模 | 必须 |
| 列名清单 | 确认字段语义 | 必须 |
| 单行样本 | 证明数据可读 | 必须 |
| 全表导出 | --- | 不必要,且风险显著 |


只读原则 整个过程没有写入、更新、删除任何记录,也没有在服务器上生成文件。验证到「能读到不应读到的数据」这一点就足够定级;继续扩大范围只会增加风险,不会增加结论。
四、第五步:把发现写成可复现的记录
记录的价值等于它的可复现性。一份合格的记录至少回答五个问题:在哪、什么条件、怎么判断的、影响多大、有没有被挡住。
| 字段 | 示例写法 | 常见错误 |
|---|---|---|
| 位置 | 接口路径 + 参数名 + 方法 | 只写域名,别人找不到入口 |
| 前置条件 | 登录态 / 防护级别 / 依赖会话 | 不提会话,复现时全部失败 |
| 判断依据 | 真条件返回列表、假条件返回空 | 只说「存在注入」,没有证据 |
| 影响 | 可读库名、表名、单行样本 | 写成「可读全库」,超出已验证范围 |
| 阻断情况 | 哪一层拦截、什么表现 | 被拦就当作不存在 |
五、修复建议要落到具体位置
定级之后最容易敷衍的一步是修复建议。写「请加强输入校验」等于没写。有效的建议必须指明改哪里、怎么改、为什么这样改有效。
| 优先级 | 改什么 | 怎么改 | 为什么有效 |
|---|---|---|---|
| P0 | 查询构造方式 | 参数化预编译,变量走绑定 | 语法与数据分离,输入无法改变语句结构 |
| P0 | 参数类型 | 入参强制转换并校验范围 | 数字型入口不接受表达式 |
| P1 | 数据库账号 | 只授予该业务必需的读权限 | 即使注入成立,影响半径也被压缩 |
| P1 | 错误与文件能力 | 关闭详细报错,禁用文件读写能力 | 减少回显位,掐断写入落地路径 |
| P2 | 检测与告警 | 对高频同源相似请求设阈值 | 盲注类行为必然高频,可被识别 |
六、这一周的六个结论
| 天 | 主题 | 最值得带走的一句 |
|---|---|---|
| Day015 | 原理 | 漏洞的根源是数据被当成了语法 |
| Day016 | 手工推理 | 每一步都对应一道可以被堵死的门 |
| Day017 | 工具 | 工具给的是分类结果,不是证明 |
| Day018 | 盲通道 | 信息量决定速率,速率决定是否留痕 |
| Day019 | 过滤失效 | 黑名单处理的是形状,不是身份 |
| Day020 | 综合验证 | 换防护级别,要换观察方式 |
| Day021 | 收尾 | 能复现的记录才有价值 |
-
注入的本质是拼接,修复的本质是分离。所有绕过的讨论,最后都指向这一句。
-
过滤不等于安全。看到的「被拦住」,往往只是换了一种表达的成本变高。
-
能复现才算结论。一次成功可能只是缓存抖动,稳定复现才是证据。
-
只读到该读的就停手。验证到能证明影响即可,扩大范围只增风险。
七、下周预告
注入这一层过了之后,下一周进入文件相关的风险面:上传、包含、以及「上传成功之后它到底落在哪」这个最容易被忽略的问题。
全部验证均在本机自建靶场完成,遵循只读与最小影响原则。真实环境中的任何验证都必须先获得书面授权,并严格控制在授权范围内。