跳转至

验证真实的 HTTP/3 MITM 捕获

这个可选的 Linux 实验室通过 REA 的公共 CLI 和 MCP 检查原生 mitmproxy 捕获。它不改变任何运行时契约或适配器,仅确立此处演练的特定生产者、模式和客户端。

准备一个可丢弃的客户机

演练所用的镜像是 Omarchy 4.0.4, build 440,SHA-256 为 43412b896fe3d730e373a51a8acf99343d7c3e6dee78aa9f9bd7fca181127264。在主机上下载它,但不要安装客户机软件包;检查其摘要,并以该文件作为只读后端镜像使用一个新的 qcow2 覆盖层。匹配的启动构件包括内核、initrd、cmdline 和上游 vm-boot 配方。使用新的 SSH 密钥、环回转发和客户机磁盘;不要复用其他调查的可写覆盖层或主机信任配置。在切换覆盖层之前关闭客户机。保留镜像和启动构件的哈希作为证据。

这个封闭的客户机已提供 cURL 8.22.0(含 OpenSSL 3.6.4、ngtcp2 1.25.0、nghttp3 1.18.0 和 nghttp2 1.70.0)。不需要客户机滚动升级软件包。 开始前运行 curl --version 并验证 HTTP2 和 HTTP3 特性。来自其他发行版的标配 cURL 可能不包含 HTTP/3。对于其他客户机,构建 cURL 需要兼容的 TLS 库、ngtcp2 和 nghttp3;遵循官方构建说明,安装到客户机私有前缀,并记录确切的源码修订版本和构建输入。该替代路径尚未由本实验室演练;它不是固定的复现路径。

在封闭的 Linux 镜像之上使用全新的 VM 覆盖层。使用绑定到主机环回的用户态网络和 SSH 转发;保持主机目录未挂载。在客户机内部安装并构建依赖项,然后在生成流量之前移除其默认路由。主机信任、路由和已安装软件包保持不变。

记录镜像摘要、REA 源码修订版本和以下依赖版本:

  • REA 的 .nvmrc、package.json#packageManager 和锁定的 npm 依赖。
  • 官方 Linux x86_64 mitmproxy 12.2.3 独立归档。SHA-256: 2e95286b618fa6fd33e5e62a78c2e5112571d85f42ec2bac29b97ee242bdb5c5。
  • 一个使用 scripts/fixtures/http3-lab-requirements.txt 中完整固定依赖图的私有 Python 虚拟环境。保存 pip freeze 和构建/下载日志。
  • 在 curl --version 中通告 HTTP3 和 HTTP2 的 OpenSSL 和 cURL。

已验证的客户机使用 Python 3.14.7、cURL 8.22.0、ngtcp2 1.25.0 和 nghttp3 1.18.0。其他依赖配置需要验证。在添加 127.0.0.1 lab.test 之前,备份客户机的 /etc/hosts。保留客户机 TCP/UDP 环回端口 18443 和 19443。这些更改仅属于可丢弃的客户机。

在客户机的 REA 检出中,使用其固定的 Node/npm 工具链:

npm ci
npm run build:cached
python3 -m venv /absolute/lab/venv
/absolute/lab/venv/bin/pip install --no-deps -r scripts/fixtures/http3-lab-requirements.txt
/absolute/lab/venv/bin/pip check
/absolute/lab/venv/bin/pip freeze > /absolute/lab/python-requirements.txt

在移除客户机默认路由之前,下载官方 mitmproxy 归档并验证它,然后解压到客户机的私有工具目录:

mkdir -p /absolute/lab/tools
curl --fail --location https://downloads.mitmproxy.org/12.2.3/mitmproxy-12.2.3-linux-x86_64.tar.gz \
  --output /absolute/lab/mitmproxy.tar.gz
printf '%s  %s\n' 2e95286b618fa6fd33e5e62a78c2e5112571d85f42ec2bac29b97ee242bdb5c5 \
  /absolute/lab/mitmproxy.tar.gz | sha256sum --check --strict
tar -xzf /absolute/lab/mitmproxy.tar.gz -C /absolute/lab/tools
/absolute/lab/tools/mitmdump --version

使用 git rev-parse HEAD 或归档 SHA-256 固定 REA 修订版本。使用精确的 .nvmrc 和 npm 版本进行构建;不要复制其他检出的 dist。为了更强的离线依赖复现,请连同镜像和工具链一起保留下载的 Python 归档、其摘要和构建出的 wheel。需求版本固定的是运行时依赖图,而不是每个临时构建工具;源码构建和替代解释器不保证字节一致。

运行这个狭窄的配置

选择绝对路径的可执行文件和一个新的证据目录。生产者拒绝重用目录。系统信任库中不安装任何证书;客户端和代理会收到显式路径,指向新生成的测试 CA。

REA_MITMDUMP_COMMAND=/absolute/lab/tools/mitmdump \
REA_HTTP3_PYTHON_COMMAND=/absolute/lab/venv/bin/python \
npm run verify:web:http3 -- /absolute/evidence/run-1

生产者通过 mitmproxy 反向模式,在一条 HTTP/3 连接上向同一个 URL 发送三个并发的二进制 POST,目标为 aioquic HTTP/3 源站。源站等待所有请求完成,然后按完成顺序的逆序分发响应。QUIC 流的发送/接收顺序不必一致。一次仅使用 HTTP/3 的 cURL 请求检查第二种客户端实现。mitmproxy 的真实保存插件写入 normal.mitm;不合成任何原生流。

第二次代理运行会禁用 HTTP/3。cURL --http3 回退到 HTTP/2,到达一个 HTTP/1.1 TLS 测试源站。fallback.mitm 必须保留这些较低版本协议,因此一个成功的 HTTP 请求不能伪装成 HTTP/3 成功。

验收与证据

每次执行都会创建 verifications/<run-UUID>/,并带有自己的诊断信息。verification-latest.json 属于最近注册的尝试,并以原子方式从 running 变为 passed 或 failed。注册以及所有权检查/替换使用同一个 SQLite 事务锁。较晚完成的较早尝试保留自己的报告,不会替换该标记。只要尝试可能运行,.verification-lock.sqlite 路径名就必须保留在原处;SQLite 会在连接关闭或进程终止时释放锁。锁获取会等待当前所有者,没有超时或租约窃取。验证器对每个命令有截止时间,但没有整体运行截止时间;因此,一个存活但停滞的锁所有者可以延迟发布,直到它退出。只有成功的尝试在完成所有清理和输入完整性检查后,才写入自己的 verification.json。result.json 还会将失败和原始错误与清理错误分开记录。较旧的成功记录保留在已标识的历史中;旧版根级 verification.json 会在重新运行前归档。被终止的验证器可能留下 running 状态,这绝不能解释为成功。

捕获输入存放在 captures/ 中。若要在不产生新流量的情况下再次检查它们,可以运行:

REA_MITMDUMP_COMMAND=/absolute/lab/tools/mitmdump \
npm run verify:web:http3 -- /absolute/evidence/run-1 --inspect-existing

当前运行的验收标准:

  • 每个正向的原生记录都会在两条链路上报告 HTTP/3、UDP、ALPN h3 以及成功的 TLS 时间戳。连接 ID、生产者 TLS 标签、精确的 TLS 建立时间戳和连接错误,与每条链路上通过 UUID 匹配的生产者观察结果一致。端点握手独立地观察到 QUIC v1。
  • 原生流 UUID 保持唯一。每条链路上有三个端点流共享一个连接。源站分发会将已完成的接收顺序反转。客户端与捕获的顺序均被观测;关联验证则独立于它们的顺序。
  • CLI 和 MCP 保持一致。请求/响应字节、长度、SHA-256、有序重复头、方法、scheme、authority 和路径均与独立观察结果匹配。可读的头名称和值、请求 URL 字段以及 ALPN 也匹配;非 UTF-8 头字节保留 null 显示值,而不是替换文本。
  • 实际的 MCP 通告 schema 验证通过;Evidence 保留源摘要和提供者来源;返回的完整 Evidence 与保留的 MCP 会话记录匹配。
  • 回退捕获报告客户端经 TCP 的 HTTP/2 以及源站 HTTP/1.1,同时 cURL 独立报告版本 2。输入文件保持不变。
  • 每次清理操作都会在成功和失败时被尝试,最终血缘关系不包含存活的子代。已记录的生产者组会在令牌验证的清理之后被单独检查,包括在其启动程序退出之后。

保留捕获文件、端点/生产者 JSONL、代理诊断、cURL 输出、清单、CLI/MCP 输出、通告的 schema 和会话包。分别导出公共证书及依赖/源代码出处。不要提交证据、私钥、依赖项或虚拟机磁盘。导出证据后关闭来宾系统。

反向代理可以在记录源站端口 19443 的同时,保留 authority lab.test:18443。Mitmproxy 序列化的 flow/connection UUID 不是流 ID。端点流 ID 是作用域化的观察结果;本测试不引入任何跨链路映射。Mitmproxy 12.2.3 的 QUICv1 标签本身并不能证明协商发生;该 fixture 会在固定的 aioquic 1.2.0 中检查协商得到的 _quic._version。

覆盖范围包括原生捕获、Linux 反向模式、QUIC v1 以及这些客户端。空/缺失/不完整/脱敏的 body 语义、取消、重置、证书失败、畸形捕获、HAR 和 qlog 属于单独的增量。本地/WireGuard、浏览器、QUIC v2、迁移、0-RTT、mTLS、重放、持续负载和丢包容忍度尚未由本配置文件验证。通过该配置文件并不代表 REA 已具备通用的 HTTP/3 支持。

官方参考资料:mitmproxy 协议支持、HTTP/3 实现、序列化的 HTTP 状态、aioquic 配置。

验证器回归测试

构建 REA 后,在同一个隔离的来宾系统中运行以下命令:

node --test scripts/lib/http3-verifier-lifecycle.test.mjs scripts/lib/http3-capture-assertions.test.mjs
/absolute/lab/venv/bin/python scripts/fixtures/http3-lab.test.py

这些测试覆盖不同的 QUIC 流完成顺序、过期的成功报告、多次失败的关闭、独立拥有的进程组和部分获取的资源,以及两条链路上生产者 TLS 事实不匹配、可读字段被修改而二进制证据未变的情况。它们测试的是验证器语义;它们并不增加 HTTP/3 提供者的覆盖范围。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 rea2/rea