Skip to content

第 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 个高危里有两个是阻断级。

本章给的工作流是三段式:

text
黑盒侦察(出初版) → 独立红队 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 端点矩阵是教科书级示例:

text
/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 元数据默认文案)初版根本没去抓。

技术正确的指纹置信度排序(从强到弱):

text
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__。正确判据按置信度排序:

  1. 【最强】多次请求同一 URL,body 字节级是否完全相同 → 相同 = 静态
  2. 【强】window.__NUXT__ 是否为空对象 → 空 = 无服务端数据获取,倾向 SSG/SPA
  3. 【强】last-modified 是否历史构建时间 → SSR 动态响应通常不返回或接近当前时间
  4. 【中】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 会沿着同一条链走,失去对抗性。让它从证据重新推一遍,才能发现初版的推理漏洞。最小可用任务卡:

text
目标:对以下初版架构结论做对抗式审查
范围:仅基于所附原始证据,不从外部假设
约束:允许少量只读 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

#原结论裁决依据
ANuxt 3 SSR推翻 → SSGbody 字节级一致;各路由固定长度;last-modified 同为构建时刻;无 Set-Cookie
BRuoYi 改造版维持,钉死为 3.8.4 原版/v3/api-docs 原版 Swagger 文案 标题:若依管理系统_接口文档 / 版本号:3.8.4
C/api/* 走 Nitro BFF降级仅证经容器 xhs_web_ui,未证 Nitro 身份
DCloudflare 仅 DNS维持 + 交叉验证TLS = Let's Encrypt R12(CF 代理必签 cloudflare 证书)
E源站 IP 暴露,高危推翻 → 信息级没上 CDN 的 IP 本就公开;server: nginx 无版本号是好评
F容器名泄漏,中危降级 → 低危利用需先有 SSRF 链到内网
GDocker Compose维持服务名含下划线,K8s Service 名不允许,Compose 允许
H安全头几乎全缺推翻 → 样本偏差/prod-api/* 实测有 nosniff + HSTS;真问题缩窄为全局缺 CSP + X-Frame-Options
I缓存"完美"删溢美词immutable+hash 是通用正确实践,非"完美"

26.6.3 漏报的 4 个高危(初版最大失分)

这是对抗式审查最有价值的产出——不是推翻已有结论,而是挖出初版根本没看到的盲区。

  1. 【高危】Druid 监控面板公网可达:/prod-api/druid → 302 重定向到登录页。RuoYi 默认集成的 SQL 连接池监控,登录页常被弱口令爆破,是 RuoYi 系最经典失分项。
  2. 【高危】Swagger 接口文档完全公开:/prod-api/v2/api-docs(62KB)+ /v3/api-docs(60KB)均 200,完整暴露 12 个 controller,含 pay-callbackwx-payapi-key-infoproxy-monitor 等涉及支付/密钥/代理的敏感接口。生产环境必须在 application.yml 关 Swagger。
  3. 【中危】验证码形同虚设:captchaImage 连续请求返回相同的 110 字节固定值(红队连打 5 次 sha256 相同)。验证码被关 → 登录只剩弱口令;或被改成固定 token(可重放)。
  4. 【中危】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 的实战应用,三段式落地为最小编排:

text
主代理(Plan Mode):
  1. 跑黑盒侦察(OSINT + 端点矩阵 + 指纹)
  2. 输出初版结论(每条标注证据)
  3. 派独立红队子代理(全新上下文,喂证据+结论,要 verdict)
  4. 收红队 verdict,列出争议点
  5. 自跑裁决性实测,钉死争议
  6. 输出最终报告(含推翻/降级/维持对照表 + 漏报项)

编排要点:

  1. 红队子代理必须全新上下文。复用主代理上下文 = 沿同一推理链走 = 失去对抗性。第 19 章的子代理天生是独立上下文,这是它比主代理自查强的根本原因。
  2. 红队子代理只读。审查阶段不允许改任何东西,连请求也要克制在最少 GET。侵入测试是另一阶段,且需明确授权。
  3. 红队任务要带 verdict 定义。不要说"审一下我的结论",要说"逐条标 verdict:证据充分/过度推断/逻辑跳跃/措辞错误/可证伪未证伪,允许少量只读验证"。
  4. 主代理负责裁决,不是红队。红队标争议,主代理跑实测钉死。这个分工防止红队变成另一个"自圆其说"的 agent。
  5. 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 项目 | 返回目录