面向暴露防护型安全扫描的内容盲反向代理
用于内容盲测安全扫描的本地反向代理。
Go · 本地 HTTPS · HTTP 与 WebSocket · Tor / SOCKS5
理由 / 工作原理 / 快速开始 / 证书 / Tor / CAPTCHA / 证据 / 开发
安全测试是一门行为学科。应用程序做什么——如何处理输入、执行哪些控制、回显什么内容、如何失败——才是关键。身份对此分析应当无关紧要。
AI 辅助安全工具并非如此运作。它们看到目标——其域名、品牌、组织——便形成判断。它们对知名服务弱化发现。它们基于目标是谁而拒绝探测。它们拒绝测试与特定供应商相关联的路径。AI 正在做出本应属于操作员的决定,而且它基于上下文而非行为做出这些决定。
这是错误的维度。操作员授权范围。工具评估行为。这是不同的职责,不应混为一谈。但如今,每个 AI 辅助工具都将目标的完整身份接入其做出的每一个决定——测试什么、施压多大、是否报告。
Blinder 是一个起点:一个实用工具,同时也是一种立场,即测试应与上下文分离。这是将这一理念传播出去的早期尝试。如果这一方法引起共鸣,我们欢迎更好的实现、贡献,或者仅仅是关于界限应划在哪里的讨论。
剥离身份并不意味着剥离内容。这正是大多数朴素方法失效之处。漏洞可观察为响应内容的变化——错误消息、反射输入、会话不应触及的数据、揭示服务端求值的计算结果。如果代理剥离了这些内容,就会隐藏测试者正在寻找的证据。
需求是精准的:移除身份,同时保留行为信号。一个不属于任何人但行为与原始页面完全一致的页面——包括在其行为不端时。
Blinder 是一个本地 HTTPS 反向代理,位于 AI 扫描器(或浏览器)与目标之间。它重写身份——域名、品牌、组织名称、电子邮件、IP 地址——同时保留应用程序的功能行为:其错误、其反射、其安全控制、其状态码、其内容结构。
对下游 AI 而言,目标是位于 https://127.0.0.1:8099 的匿名本地托管应用程序。没有品牌可识别。没有域名可供形成判断。AI 测试应用程序做什么,而非它是谁。
这就是内容盲测扫描:操作员控制目标是谁;AI 专注于它做什么。
替换内容是正确性的一部分:用于显示的中性填充、用于应用程序数据的可逆值,以及保留的诊断和控制行为。生成的移除通知不应出现在页面中。
| 内容清洗 | 显示文本替换为中性散文填充;交互元素(按钮、标签、表单控件)和诊断内容(错误消息、堆栈跟踪、反射标记)保留。身份令牌、域名引用和 cookie 值在 HTTP 正文、标头和 WebSocket 文本中重写。--preserve-content 保留原始显示文本,仅进行身份清洗。 |
| 资源完整性 | 按引用验证原始 SRI,并为重写后的资源重新计算,同时转换相应的 CSP 哈希。带版本的引用绑定所服务的字节;外部资源完整性得以保留。 |
| 响应缓存 | 分离的上游/下游缓存验证器。304 重新验证合并安全策略标头。感知 Vary 的逐出。 |
| 会话处理 | 可逆的 cookie 名称,按值清洗。通过 --extra-origin 进行多源路由,具有确定性别名主机名、Host 标头路由和 CORS 源转换。 |
| CAPTCHA 中继 | 面向操作员的挑战队列和独立的提供商源。Tor 路由的资源将提供商 cookie、CSP 和 CORS 与目标和操作员分开。 |
| 私有路由 | 通过 Tor SOCKS5 进行上游 HTTP 和 WebSocket,具有远程主机名解析。Tor 故障是硬错误,绝不静默回退。 |
| 本地 HTTPS | 本地 CA,90 天有效期并自动续期;会话叶证书即时签名。信任 CA 一次——添加源或更改别名无需重新信任。提供临时模式。 |
| 证据 | 基于日志持久化的清洗前 HAR,带每请求清洗/泄漏计数的请求清单、域名映射和清洗报告。配对响应比较检查字节大小保真度以及内容/状态变化是否在掩码后保留。信号保留检查记录已验证的行为和剩余缺陷。 |
有关实现状态和已知限制,请参阅支持的行为和交付门禁。
使用 Go 1.26+ 构建。该二进制文件没有外部运行时依赖。
git clone https://github.com/Splinters-io/blinder.git
cd blinder
make build
./blinder --preflight
遵循操作系统特定的证书建议,然后启动会话:
capture_dir=$(mktemp -d)
./blinder --target https://your-authorized-target.example \
--identity YourOrganisation \
--har "$capture_dir/session.har" \
--output "$capture_dir/output"
将浏览器或扫描器指向 https://127.0.0.1:8099。使用重复的 --identity 标志添加多个身份令牌。使用 Ctrl-C 停止以保存会话证据。
使用 --config(-c)从 YAML 文件加载默认值。CLI 标志覆盖文件。
# blinder.yaml
listen: "127.0.0.1:9443"
target: "https://example.com"
alias: "target-001.local"
identity:
- "ExampleCorp"
- "example.com"
output: "/tmp/blinder-output"
captcha_config: "captcha.yaml"
no_verify_tls: true
tor:
enabled: false
addr: "127.0.0.1:9050"
har:
path: "/tmp/session.har"
max_body: 10485760
./blinder -c blinder.yaml
# override the listen port from the file:
./blinder -c blinder.yaml --listen 127.0.0.1:7777
Blinder 在首次运行时生成本地 CA(证书颁发机构),并使用它为会话特定的叶证书签名。信任 CA 一次;所有当前和未来的端点——包括稍后添加的额外源——都会自动信任,无需重新运行设置。
| 平台 | 设置 |
|---|---|
| macOS | 运行打印的 --trust-cert 命令,查看 CA 指纹并批准用户 Keychain 信任。一次性设置。 |
| Ubuntu / Linux | 使用打印的 curl --cacert 命令,或将 CA 证书安装到浏览器/扫描器的信任存储中。 |
使用 --cert-dir DIR 指定 CA 存储位置。CA 持续 90 天并自动续期;--ephemeral-cert 生成无 CA 的临时自签名叶证书。预检退出码 2 表示平台信任需要设置;使用自己 CA 文件的客户端仍可成功连接。
添加额外源、更改别名或重新配置 CAPTCHA 提供商会生成由同一 CA 签名的新叶证书——无需重新信任。预检报告监听主机、主别名、配置的额外源别名以及(当配置 CAPTCHA 时)操作员和具体挑战主机名的信任情况。使用 --tor 时,预检还包括配置的提供商别名。
CA 存储还保存用于资源引用所有权的私有 version-signing.key,独立于证书续期。在重启之间保留它,以便过期的引用仍可识别。--ephemeral-cert 保持 TLS 临时性;资源引用所有权仍持久保存在默认存储中。
启动 Tor 服务并等待引导完成,然后选择其 SOCKS 端点:
./blinder --target http://your-service.onion \
--tor --tor-addr 127.0.0.1:9050 \
--identity YourOrganisation
明网目标可以使用相同的路由。目标 TLS 验证保持启用。Tor 故障返回错误,不会回退到直接目标连接。
当目标返回 CAPTCHA 挑战时,Blinder 将其排队供操作员处理。通过 --captcha-config 配置提供商:
version: 1
captcha:
providers:
- hcaptcha
打开启动时打印的浏览器登录 URL:https://blinder-operator.localhost:<port>/__blinder/captcha/login?token=…。这个独立的、仅本地的源持有操作员会话。原始挑战内容在其自己的 <challenge-id>.blinder-challenge.localhost 源上通过过期的视图能力运行;操作员 cookie 保留在操作员源上。Bearer 认证仍可供 API 客户端使用。证书规划包括挑战通配符;验证所选浏览器对操作员、挑战和提供商主机名的信任。请参阅操作员和证书指南。
使用 --tor 时,每个配置的 route-with-target 提供商源获得自己的 https://captcha-<hash>.localhost:<port> 地址,并使用目标的 SOCKS 传输。静态 HTML 引用、基础 URL 和刷新导航使用这些路由。一个有界辅助程序还会在无 CSP 的提供商文档中路由动态 fetch、XHR 和 URL setter;它保持提供商脚本字节和完整性元数据不变。具有强制执行或仅报告策略的文档不会获得辅助程序。提供商错误和实际 CORS 决定保持可见,cookie 仍由浏览器控制。旧的 /__blinder/captcha/res 端点在目标和操作员源上返回 404。
内置配置文件涵盖 hCaptcha、reCAPTCHA 和 Turnstile。自定义提供商使用显式的 resource_origins、可选的 resource_url_regex、opaque_fields 和 submissions;每个中继的请求都会根据该范围进行检查。直接模式保持提供商引用不变,tor_policy: direct 仍是显式的 Tor 例外。
Chrome 完成了合成操作员流程:所有 13 个提供商请求都使用了中继,原始 POST 以其精确的解决方案令牌、会话和刷新的 CSRF 恢复。一个单独的跨站 Lax-cookie 案例保留了直接提供商的 HTTP 400 拒绝。这是有界的本地验收:CSP 限制的挑战、其他动态加载 API、实际别名信任、真实提供商人工完成以及实时 Tor/onion 验收仍待完成。可重复的浏览器检查单独记录这些门禁。
hcaptcha 和 reCAPTCHA 拒绝将 localhost 和 127.0.0.1 作为主机名。要使用这些提供商进行本地测试,请添加 hosts 条目并将该主机名用作 --target:
# /etc/hosts
127.0.0.1 uat.blinder.test
blinder --target http://uat.blinder.test:9999 ...
Turnstile 测试密钥在 localhost 上无需 hosts 条目即可工作。
| 提供商 | 测试 sitekey | 测试 secret |
|---|---|---|
| hcaptcha | 10000000-ffff-ffff-ffff-000000000001 | 0x0000000000000000000000000000000000000000 |
| Turnstile | 1x00000000000000000000AA | 1x0000000000000000000000000000000AA |
hcaptcha 测试密钥始终通过,无需视觉挑战。Turnstile 测试密钥 1x...AA 始终通过;3x00000000000000000000FF 强制交互式挑战。
将原始捕获保留在操作员一侧;它们包含真实目标数据。
安全提示: HAR 文件包含完整的清洗前 HTTP 交换,包括
Authorization、Cookie和Set-Cookie标头。它们以仅所有者权限(0600)写入,但任何能访问该文件的人都拥有该会话期间通过代理传输的所有凭据。将 HAR 文件视为机密:不要将它们提交到版本控制、未经脱敏就分享,或存储在共享文件系统上。
| 输出 | 内容 |
|---|---|
--har FILE | 清洗前的原始 HTTP 请求和响应。基于日志的持久化,定期刷新。 |
blinder-manifest.json | HTTP 结果、每请求身份/域名替换计数和泄漏计数。 |
blinder-dealias.json | 别名到原始域名的映射。 |
blinder-scrub-report.json | 记录的身份/域名匹配和聚合计数。 |
JSON 报告保存在 --output DIR 下,具有仅所有者文件权限。--har-max-body 限制每个捕获的请求/响应正文,截断记录在 HAR 中。关闭时即使其中一个失败,也会尝试输出 HAR 和报告。
make test # 768 package tests with race detection
make lint # Go vet
make test-functional # 35 functional scenarios: CLI, TLS, sessions,
# evidence, WebSocket, SOCKS5 and CAPTCHA
所有测试在 -race 下通过。浏览器级验收测试通过 BLINDER_REVIEW_BROWSER=1 选择加入。
测试和 UAT 指南 · 交付门禁 · 技术规范