Day 163 完成清单 · 安全审计工具箱(二):SQLi 检测 + XSS 检测
Phase 10 — 网络安全开发 · 阶段项目 Day 162–165 的第 2 天
⚠️ 实验只跑在本机回环靶标(
code/vuln_core.py的LabVulnHTTP)。 只对自己拥有或已获书面授权的目标做检测;只发 GET;不取数、不绕过。
✅ 一、完成清单(照着打勾)
概念与原理(读 README.md)
- [ ] 能说清阶段项目四天分工,以及"漏洞面为什么必须建立在资产面之上"
- [ ] 能写出 SQLi 检测的两段式判定条件(报错回显 / 布尔差分)
- [ ] 能解释布尔差分为什么必须锚定 baseline(而不是只比 true vs false)
- [ ] 能说出 4 个探针各自的作用,以及为什么不多发
- [ ] 能说出 XSS 检测的四层判定:反射确认 → 转义判定 → 上下文判定 → 缓解措施
- [ ] 能说出 4 种上下文的严重度,以及
<script>块为什么最高 - [ ] 能说出"探针不该是可执行载荷"的三个理由
- [ ] 能解释
close()的max(tol_abs, tol_rel×max(a,b))为什么两头都要 - [ ] 能解释优先级为什么用"严重度 × 置信度"而不是相加
- [ ] 能解释退出码
4(覆盖不完整)为什么必须独立于3(有发现)
代码与实测(在 code/ 下跑)
- [ ]
python3 vuln_core.py --self-test→SELF-TEST OK - [ ]
python3 01-sqli-detect.py→ 看到三类结果:error_based/none/none - [ ]
python3 02-xss-detect.py→ 看到四种上下文 + 两个安全对照沉默 - [ ]
python3 03-vuln-scan-cli.py --lab→ 退出码3,out/下有报告 - [ ]
python3 03-vuln-scan-cli.py --lab --throttle-after 6→ 退出码4 - [ ] 用
--targets targets.example.txt复现第 1 步的结论(可复现性) - [ ] 亲手触发一次越界(退出码
2),确认它不会重试 - [ ] 打开
out/day163-lab-report.md,逐条核对"事实 / 推断 / 待验证"的措辞
工程习惯
- [ ] 读完
README.md§9「边界与合规」表格,能复述至少 5 条及其理由 - [ ] 报告里没有出现目标响应中的原始报错全文(只出现特征名)
- [ ] 能说出今天修掉的 2 个真实坑(行尾注释 / 完整 URL 拼接)
📝 二、基础练习题(3 道)
练习 1:读懂探针表(观察题)
运行 python3 01-sqli-detect.py,把 /product 与 /echo 的输出抄下来,回答:
/product的error探针返回的状态码是多少?检测器凭什么下结论?/echo的baseline/error/true/false四个长度分别是多少? 其中"布尔差分不成立"是因为哪一条条件没满足(①②③)?- 如果把
/echo的输出给一个"只比长度"的检测器,它会得出什么错误结论?
验收标准:能用一句话说清"长度变化 ≠ 注入"。
练习 2:给检测器加一个探针并解释代价
在 vuln_core.py 的 detect_sqli() 里,把探针计划临时改成 5 个
(加一个 probe: 原值 OR 1=1),然后回答:
- 为什么
MAX_PROBES_PER_PARAM = 4会让这个改动直接抛异常而不是静默多加一次请求? - 把上限改成 5 让它能跑,观察
/safe-product的结论会不会变。为什么? - 讨论:如果一个真实工具想用 20 个探针,应该在哪里做补偿(限速?授权记录?报告?)
验收标准:能说出"硬闸门 vs 静默跳过"的设计差异,并明确它属于授权边界而非性能问题。
练习 3:上下文判定的手算
靶标 /profile?name=ops 的响应片段是:
html
<form><input name='fullname' value="【探针】"><button>保存</button></form>
- 手工执行
classify_context()的三步判断(注释 → 脚本块 → 标签内), 写出每一步的rfind比较结果。 - 为什么它判成
attr_quoted_double而不是attr_unquoted? - 如果响应写成
<input name='fullname' value='【探针】'>(单引号属性), 结论会变成什么?严重度会变吗?
验收标准:能画出"标记左边最近的未闭合结构"这张图。
🚀 三、进阶挑战题(2 道)
挑战 1:消灭"重复内容型"假阳性
背景:现在的 boolean_based 判据要求 true 贴近 baseline、
false 偏离 baseline。请构造一个会骗过它的假想端点:
- 要求:这个端点没有 SQL 注入,但检测器会报
boolean_based。 - 提示:让"响应长度"取决于输入字符串的长度本身,但差值恰好超过容差。
然后给出至少两种改进方案,并比较代价:
| 方案 | 做法 | 代价 / 新风险 |
|---|---|---|
| A | 多次采样取长度分布(去掉 1 次采样的噪声) | 请求数 ×N,撞上授权上限 |
| B | 换不变量:比较结构指纹(如 DOM 节点数、去空白后的文本长度) | 需要解析 HTML,复杂度和误判面上升 |
| C | 你的方案 | ? |
验收标准:能说清"提高检出率"与"降低误报率"在这类工具里为什么天然对立。
挑战 2:把"覆盖完整性"做成可执行的门禁
当前 coverage 只统计 throttled / errors。请扩展它,使其能回答:
- 哪些具体目标没有取得结论?(列出
url + param) - 给一个
--require-coverage 100的 CLI 选项:只要有任何目标未取得结论, 就退出码4并在报告里单开一节「未覆盖清单」。 - 思考:这算不算"检测工具的正确用法"?如果一个工具永远无法 100% 覆盖,
CI 里应该设置成
--require-coverage多少?(提示:结合"无法覆盖的原因"分类讨论: 限速 / 网络 / 门禁拒绝,哪一种应该阻断流水线?)
验收标准:产出一份"未覆盖清单" Markdown,且退出码语义与 README §2.7 表格一致。
🔍 四、自检命令(一键跑完)
bash
cd days/day-163-安全审计工具箱-part2/code
python3 vuln_core.py --self-test && \
python3 01-sqli-detect.py > /tmp/d163-01.log 2>&1 && \
python3 02-xss-detect.py > /tmp/d163-02.log 2>&1 && \
python3 03-vuln-scan-cli.py --lab > /tmp/d163-03.log 2>&1; echo "exit=$?"
grep -c "error_based" /tmp/d163-01.log
grep -c "script_block" /tmp/d163-02.log
ls out/
预期:--self-test 输出 SELF-TEST OK;最后一条命令的 exit=3;
out/ 下至少有 day163-lab-report.{json,md}。
📌 五、今日关键结论(背下来)
1. 报错特征是强证据(自证),布尔差分是弱证据(必须锚定 baseline)。
2. 长度变化 ≠ 注入:/echo 陷阱专治"只比长度"。
3. XSS 判定是四层:反射 → 转义 → 上下文 → 缓解措施,少一层就失真。
4. 探针不是载荷:检测只需证明"危险字符原样进入 HTML",无需真的执行。
5. 缺缓解措施头是事实,不是结论("缺 CSP" ≠ "有 XSS")。
6. 越界 = 退出码 2(不重试);没测完 = 退出码 4(不能当通过)。
7. 优先级 = 严重度 × 置信度:两个维度独立,不能压成一维。
8. 边界是用来让程序停下来的(硬闸门抛异常),不是用来"温柔提醒"的。