第 26 章 红队对抗式审查
第 25 章讲的是拿到源码做白盒审查;本章讲的是没有源码——或者源码不可信、需要验证真实部署防御强度——时,如何用黑盒侦察 + 独立红队 agent 对抗验证,产出一份可信的架构与安全评估。素材全部来自一次真实黑盒评估存档(anytocopy.com,2026-07-07),没有虚构。
26.1 结论:红队对抗式审查 = 黑盒侦察 + 独立红队 agent + 指纹置信度排序
红队对抗式审查(Red Team Adversarial Review)解决的是一个第 25 章覆盖不了的场景:你拿不到源码。比如评估一个第三方 SaaS、一个竞品、一个即将合作但对方只给了 URL 的系统。这时候白盒审查的 Read/Grep 全部失效,你能做的只有发 HTTP 请求看响应。
这种场景下,单 agent 侦察有一个致命缺陷:自圆其说。agent 侦察完出一份报告,里面的推断往往是"看起来合理但证据不足",而同一个 agent 复查自己时倾向留情面——它不会主动推翻自己刚下的结论。anytocopy.com 的初版分析就栽在这:9 条结论里 3 条错、3 条评级偏高,而漏报的 4 个高危里有两个是阻断级。
本章给的工作流是三段式:
黑盒侦察(出初版) → 独立红队 agent(逐条 verdict) → 裁决性实测(钉死争议)核心支点有两个:指纹置信度排序(用最强指纹定框架,别从路径名猜)和独立 agent 对抗(全新上下文,喂证据不喂推理,要逐条标 verdict)。这两点把"黑盒侦察"从一门玄学变成可复现的工程。
26.2 与第 25 章的区别:黑盒 vs 白盒
| 维度 | 第 25 章仓库级审查 | 本章红队对抗式审查 |
|---|---|---|
| 前提 | 有完整源码 | 无源码,只有 URL/端点 |
| 方法 | Read/Grep 真实代码,按维度并行扫 | HTTP 探测 + 指纹识别 + 公开信息收集 |
| 验证 | 跑测试、类型检查、运行态 | 裁决性实测(发少量 GET 请求钉死争议) |
| 对抗性 | 单次审查,主代理汇总 | 独立红队 agent 逐条质疑,推翻/降级/维持 |
| 结论性质 | 确定性(看到代码) | 概率性(推断 + 实证交叉) |
| 典型场景 | 接手新项目、发布前审计 | 第三方评估、合作前尽调、防御强度验证 |
关键区别在对抗性。第 25 章的并行子代理是"合作型"——多个 agent 各盯一维,边界不重叠,一起把覆盖率拉满;本章的红队 agent 是"对抗型"——它的任务不是补充,而是推翻初版。一个 agent 负责建,另一个负责拆,这种张力才逼出真问题。
26.3 黑盒侦察方法
黑盒侦察(Black-box Reconnaissance)的目标是在不发侵入请求的前提下,尽可能精确地还原目标的技术栈、架构与攻击面。三步走:公开信息收集 → 端口与服务探测 → 指纹识别。
26.3.1 公开信息收集(OSINT)
零请求先干活。在发任何 HTTP 请求前,先把公开信息榨干:
- DNS 记录:
dig/nslookup看 NS、MX、A、TXT。NS 在cloudflare.com= 用 CF;MX 是 Cloudflare Email Routing = 邮件也走 CF。anytocopy.com 的 NS 是fish/lex.ns.cloudflare.com,一眼定位 DNS 服务商。 - TLS 证书:
openssl s_client -connect host:443看 issuer 和 subject。这一步信息密度极高——证书签发者能反推 CDN 是否代理(见 26.4)。anytocopy.com 的 issuer 是Let's Encrypt R12,直接证明 Cloudflare 没代理源站(CF 代理必签 cloudflare 证书)。 - ICP 备案(中国站点):whois 或工信部查询,能定位主体。anytocopy.com 是浙ICP备2024055286号-10。
- 广告与统计 ID:页面里的
pub-xxxx(AdSense)、G-xxxx(GA4)、百度统计 ID 是变现模式的铁证,还能用来反查同主体下其他站点。
26.3.2 端口与服务探测
这一步要克制。nmap 全端口扫描对第三方站点是侵入性的,本章工作流默认只发 GET 请求,端口探测限于 80/443 与已知业务端口。CLAUDE.md 红线里的"风险命令"和"破坏性修改"同样适用——未授权的端口扫描在很多司法管辖区是违法的(见 26.8)。
探测的核心是端点矩阵:针对识别出的框架,列一组已知默认端点,逐个 GET 看响应。anytocopy.com 的 RuoYi 端点矩阵是教科书级示例:
/prod-api/ -> 200 text/plain 128B (base64 密文)
/prod-api/v3/api-docs -> 200 application/json 59911B
/prod-api/v2/api-docs -> 200 application/json 62276B
/prod-api/swagger-ui/index.html -> 200 text/html 3129B
/prod-api/druid -> 302
/prod-api/getInfo -> 401 application/json 128B
/prod-api/login -> 200 application/json 55B
/prod-api/captchaImage -> 200 application/json 110B
/prod-api/actuator -> 401一张矩阵同时回答三个问题:是不是 RuoYi、哪个版本、哪些高危端点误开公网。
26.3.3 指纹识别(技术栈/框架/版本)
指纹识别(Fingerprinting)是黑盒侦察的核心。从 HTTP 响应头、HTML 结构、JS bundle 命名、错误页、默认文案里反推技术栈。anytocopy.com 的指纹散落在五处:
- HTML 内嵌 importmap:
{"imports":{"#entry":"/_nuxt/9AwefVIF.js"}}+__NUXT_DATA__+window.__NUXT__→ Nuxt 3 - JS 懒加载特征:
__vite__mapDeps→ Vite 构建 - CSS reset:
--tw-content→ Tailwind CSS - sitemap 路由:
/、/en、/zh-TW→ i18n 三语 - 404 错误页:内部服务名
xhs_web_ui当主机名解析 → 容器化部署
但指纹有强弱之分,这正是 26.4 要讲的。
26.4 指纹置信度排序:多源交叉验证
黑盒侦察最大的坑是用最弱的证据下最强的结论。anytocopy.com 初版锁定 RuoYi 用了两条证据:/prod-api 前缀 + captchaImage 端点。这两条恰恰是最弱的——/prod-api 是任意项目都能用的路径名,captchaImage 的非标准响应(返回固定 110 字节,不是标准 RuoYi 验证码图)反而是反证。而最强的证据(Swagger 元数据默认文案)初版根本没去抓。
技术正确的指纹置信度排序(从强到弱):
Swagger/OpenAPI 元数据默认文案 > Druid 暴露路径 > /getRouters 端点
> captchaImage 端点 > /prod-api 前缀(接近零证据)为什么 Swagger 文案是最强指纹?因为它是配置漂移铁证。开发者改框架容易,改默认文案难——/prod-api/v3/api-docs 返回的 JSON 里写着 标题:若依管理系统_接口文档 / 版本号:3.8.4,这是 RuoYi 官方模板的原话,没人会去改。一条请求就把框架 + 版本 + 是否原版全定了。
SSR vs SSG 的判据是另一个置信度排序的典型。初版看 __NUXT_DATA__ 存在就判 SSR,错了——SSG 和 SSR 两种模式都会注入 __NUXT_DATA__。正确判据按置信度排序:
- 【最强】多次请求同一 URL,body 字节级是否完全相同 → 相同 = 静态
- 【强】
window.__NUXT__是否为空对象 → 空 = 无服务端数据获取,倾向 SSG/SPA - 【强】
last-modified是否历史构建时间 → SSR 动态响应通常不返回或接近当前时间 - 【中】
content-length + last-modified + etag三件套稳定出现 → 静态文件签名
anytocopy.com 的裁决性实测:两次 GET / content-length 都是 174941、last-modified 都是 Fri, 03 Jul 2026 03:21:23 GMT(构建时刻)、无 Set-Cookie → SSG 实锤。
TLS 证书判 CDN 代理同理:CF 代理必签 cloudflare 证书,LE/ZeroSSL = 源站直连。这一条交叉验证了 DNS 层的"未代理"结论。多源交叉验证是置信度排序的落脚点——单一证据不可信,两个独立维度指向同一结论才可信。
26.5 独立红队 agent 对抗审查工作流
这是本章的核心方法论。三段式工作流:
26.5.1 第一阶段:侦察 agent 出初版
主代理(或侦察 agent)跑 26.3 的黑盒侦察,输出一份初版架构结论。这一步允许推断,但每条结论必须标注证据。anytocopy.com 初版出了 9 条,涵盖前端框架、后端框架、基础设施、变现、缓存、风险。
26.5.2 第二阶段:独立红队 agent 逐条 verdict
这一步是工作流的灵魂。派一个全新上下文的独立子代理(第 19 章 Subagents),喂给它全部原始证据 + 初版结论,要求逐条标 verdict:
- 证据充分(solid)
- 过度推断(overreach)
- 逻辑跳跃(leap)
- 措辞错误(wording)
- 可证伪未证伪(unfalsified)
关键纪律:不喂结论的论证过程,只喂证据和结论本身。如果喂了初版的推理链,红队 agent 会沿着同一条链走,失去对抗性。让它从证据重新推一遍,才能发现初版的推理漏洞。最小可用任务卡:
目标:对以下初版架构结论做对抗式审查
范围:仅基于所附原始证据,不从外部假设
约束:允许少量只读 GET 验证;禁止侵入测试
完成输出:逐条标 verdict(solid/overreach/leap/wording/unfalsified)
+ 给出推翻/降级/维持的裁决依据
+ 列出初版漏报的盲区红队 agent 就是这一步抓出了"安全头全缺"是样本偏差——它去测了 /prod-api/*,发现其实有 nosniff + X-XSS-Protection + HSTS,初版只看了首页 / 就下了全局结论。
26.5.3 第三阶段:裁决性实测钉死争议
红队标出争议点后,主代理自跑裁决性实测(empirical adjudication),用最少请求钉死最多争议。anytocopy.com 跑了三组实测:
- SSR/SSG:连续两次首页比对 + 多路由 last-modified + Set-Cookie 检查
- RuoYi 版本:端点矩阵 +
/v3/api-docs前 300 字节 - CDN 代理:
openssl s_client看证书签发者
三组实测推翻 3 条、降级 3 条、维持 3 条,并挖出 4 个初版漏报的高危。这个"推翻率"恰恰说明对抗式审查的必要性——单 agent 自查绝不会推翻自己 1/3 的结论。
26.6 实战案例:anytocopy.com 全程
26.6.1 初版 9 条结论(含后续被推翻项)
初版判断 anytocopy.com 是「Nuxt 3 SSR + RuoYi 改造版 + nginx + Docker Compose + Cloudflare 仅 DNS」,并列出 4 条风险:源站 IP 暴露(高危)、容器名泄漏(中危)、安全头全缺、HSTS 偏弱。
26.6.2 红队裁决:推翻 3 / 降级 3 / 维持 3
| # | 原结论 | 裁决 | 依据 |
|---|---|---|---|
| A | Nuxt 3 SSR | 推翻 → SSG | body 字节级一致;各路由固定长度;last-modified 同为构建时刻;无 Set-Cookie |
| B | RuoYi 改造版 | 维持,钉死为 3.8.4 原版 | /v3/api-docs 原版 Swagger 文案 标题:若依管理系统_接口文档 / 版本号:3.8.4 |
| C | /api/* 走 Nitro BFF | 降级 | 仅证经容器 xhs_web_ui,未证 Nitro 身份 |
| D | Cloudflare 仅 DNS | 维持 + 交叉验证 | TLS = Let's Encrypt R12(CF 代理必签 cloudflare 证书) |
| E | 源站 IP 暴露,高危 | 推翻 → 信息级 | 没上 CDN 的 IP 本就公开;server: nginx 无版本号是好评 |
| F | 容器名泄漏,中危 | 降级 → 低危 | 利用需先有 SSRF 链到内网 |
| G | Docker Compose | 维持 | 服务名含下划线,K8s Service 名不允许,Compose 允许 |
| H | 安全头几乎全缺 | 推翻 → 样本偏差 | /prod-api/* 实测有 nosniff + HSTS;真问题缩窄为全局缺 CSP + X-Frame-Options |
| I | 缓存"完美" | 删溢美词 | immutable+hash 是通用正确实践,非"完美" |
26.6.3 漏报的 4 个高危(初版最大失分)
这是对抗式审查最有价值的产出——不是推翻已有结论,而是挖出初版根本没看到的盲区。
- 【高危】Druid 监控面板公网可达:
/prod-api/druid→ 302 重定向到登录页。RuoYi 默认集成的 SQL 连接池监控,登录页常被弱口令爆破,是 RuoYi 系最经典失分项。 - 【高危】Swagger 接口文档完全公开:
/prod-api/v2/api-docs(62KB)+/v3/api-docs(60KB)均 200,完整暴露 12 个 controller,含pay-callback、wx-pay、api-key-info、proxy-monitor等涉及支付/密钥/代理的敏感接口。生产环境必须在application.yml关 Swagger。 - 【中危】验证码形同虚设:
captchaImage连续请求返回相同的 110 字节固定值(红队连打 5 次 sha256 相同)。验证码被关 → 登录只剩弱口令;或被改成固定 token(可重放)。 - 【中危】RuoYi-Vue 3.8.4 是 2022 老版本:依赖链(Spring Boot 2.5.x / Druid 1.2.x / 可能的 Fastjson)在 2024–2026 有多个公开 CVE。
/prod-api/actuator返回 401 说明 Actuator 已开仅被鉴权拦截,可继续试探/actuator/env、/actuator/heapdump。
额外发现:/prod-api/* 所有响应(含 401 错误)body 都是 base64 密文——后端启用全局响应体加密(ResponseBodyAdvice),连错误响应都被加密。安全增强,但前端 JS bundle 内有对称解密逻辑,密钥/算法可反推。
26.6.4 最终架构定论
anytocopy.com = Nuxt 3 SSG 预渲染静态前端(Vite + Tailwind,i18n 三语)由 nginx 直出 + RuoYi-Vue 3.8.4(Spring Boot 2.5.x)业务后端,启用全局响应加密 + Druid + Swagger(均误开公网)+ Docker Compose 编排(内网容器名
xhs_web_ui),Cloudflare 仅做 DNS,Let's Encrypt 证书源站直连。变现走 AdSense + 订阅(支付/订单 controller 已就位)。
一句话评价:业务/产品层做得专业(SSG + i18n + SEO 结构化数据 + 长缓存 + 支付订阅),后端安全加固严重不足(Druid/Swagger 公网暴露、老版本依赖、验证码失效)——典型的"前端产品成熟、后端运维裸奔"的小团队 SaaS。
26.7 用 Claude Code 编排红队工作流(预告第 19/20 章)
本章工作流的"独立红队 agent"就是第 19 章 Subagents 的实战应用,三段式落地为最小编排:
主代理(Plan Mode):
1. 跑黑盒侦察(OSINT + 端点矩阵 + 指纹)
2. 输出初版结论(每条标注证据)
3. 派独立红队子代理(全新上下文,喂证据+结论,要 verdict)
4. 收红队 verdict,列出争议点
5. 自跑裁决性实测,钉死争议
6. 输出最终报告(含推翻/降级/维持对照表 + 漏报项)编排要点:
- 红队子代理必须全新上下文。复用主代理上下文 = 沿同一推理链走 = 失去对抗性。第 19 章的子代理天生是独立上下文,这是它比主代理自查强的根本原因。
- 红队子代理只读。审查阶段不允许改任何东西,连请求也要克制在最少 GET。侵入测试是另一阶段,且需明确授权。
- 红队任务要带 verdict 定义。不要说"审一下我的结论",要说"逐条标 verdict:证据充分/过度推断/逻辑跳跃/措辞错误/可证伪未证伪,允许少量只读验证"。
- 主代理负责裁决,不是红队。红队标争议,主代理跑实测钉死。这个分工防止红队变成另一个"自圆其说"的 agent。
- Workflows 编排(第 20 章):对于需要反复评估多个站点的场景,可以把这套三段式固化成 Workflow,输入 URL,输出统一格式的报告。
26.8 合规与授权边界
本章工作流有一个不可逾越的前提:仅在授权范围内进行。CLAUDE.md 红线边界里,"破坏性修改"和"风险命令"两条直接约束安全测试:
- 未授权扫描的法律风险:在中国,《网络安全法》和《刑法》第 285 条(非法侵入计算机信息系统罪)对未授权访问有明确刑罚。即便只发 GET 请求,大规模端口扫描、目录爆破、漏洞探测都可能被认定为"侵入"。anytocopy.com 的评估之所以全程只发少量 GET、且仅针对公开端点,就是因为这属于"公开可访问信息的收集",不是"侵入测试"。
- 授权范围要明确:授权不是"对方说可以就行",要写清楚范围(哪些域名/IP、哪些端点、是否允许爆破、是否允许 DoS)。口头授权在法律上等同于无授权。
- 发现高危不等于可以验证:侦察发现 Druid 公网可达,不意味着你可以去爆破弱口令"验证"它。从"发现暴露"到"主动利用"之间有一道法律红线,本章工作流只到"发现暴露"为止。
- 报告交付对象:评估报告只交付给授权方。把第三方站点的漏洞详情公开披露(即使出于"负责任披露")在很多司法管辖区仍可能违法。
Claude Code 在执行这类任务时,主代理应主动在 Plan 阶段声明授权范围,红队子代理的任务卡里也要写死"仅 GET、仅授权端点"。这不仅是纪律,是法律自我保护。
26.9 失败边界
三种做法会让对抗式审查失效:
失败一:红队 agent 同质化,失去对抗性。如果红队 agent 和侦察 agent 用同一个模型、同一套 prompt 风格、喂同样的推理链,它会沿初版的思路走,最多修修措辞。保持对抗性的关键是全新上下文 + 只喂证据不喂推理 + 明确要求 verdict。anytocopy.com 的红队能推翻 3 条,正是因为它从证据重新推了一遍,发现"安全头全缺"这个结论的证据只来自首页 / 一个样本。
失败二:指纹误判,用弱证据下强结论。初版用 /prod-api 前缀判 RuoYi 就是典型——路径名是任意项目都能用的,接近零证据。指纹置信度排序的意义就是强迫自己先用强指纹(Swagger 元数据、Druid 路径),弱指纹只做佐证。一旦用弱指纹定了框架,后续所有推断都建立在错误地基上。
失败三:未授权扫描的法律风险。这是最严重的失败——不是审查错了,是审查本身违法。黑盒侦察的边界非常清晰:公开信息收集(DNS/TLS/ICP)和针对公开端点的少量 GET 请求是安全的;端口扫描、目录爆破、漏洞利用需要明确授权。混淆这两者的后果不是"审查质量差",是法律追责。
边界之外:黑盒侦察的结论本质是概率推断,不是确定性结论。即便用了置信度排序和交叉验证,仍有误判可能。anytocopy.com 的最终定论里,/api/* 是否走 Nitro BFF 仍被降级为"无法证实"——这就是诚实的边界。黑盒审查报告的每条结论都应标注置信度(高/中/低),低置信度的结论不能当事实用。
26.10 小结
红队对抗式审查的三段式——黑盒侦察出初版、独立红队 agent 逐条 verdict、裁决性实测钉死争议——本质上是把"黑盒分析"从一个 agent 的主观推断,变成两个独立视角的对抗 + 实证裁决。这与第 06 章的核心心法一脉相承:你定授权范围和置信度标准,Claude 做侦察和初筛。
指纹置信度排序是这套方法论的支点:用最强指纹定框架,别从路径名猜。Swagger 元数据默认文案 > Druid 暴露路径 > /getRouters > captchaImage > /prod-api 前缀——这个排序不只适用于 RuoYi,任何框架识别都应先抓"配置漂移铁证",再用弱指纹佐证。
与第 25 章的白盒审查互补:有源码走维度并行 + 统一分级,无源码走黑盒侦察 + 红队对抗。两套工作流的共同底色是对抗自圆其说——白盒用多个子代理边界不重叠防漏,黑盒用独立红队推翻初版防错。承认 LLM 单 agent 会自圆其说,然后用工程手段逼出对抗性,这是 Claude Code 做安全审查的工程纪律。
最后强调一句:黑盒侦察的边界是法律边界,不是技术边界。授权范围写不清楚,技术再好也是违法。本章工作流只覆盖"公开信息收集 + 少量 GET 探测",侵入测试需要单独的授权和专业工具,Claude Code 不应越界。
上一章:第 25 章 代码安全审查实战
下一章:RAG 与 Agent 项目 | 返回目录