HTTP/2 协议逆向:从 Fiddler 抓不到包说起

在移动应用与 Web 逆向工程的日常工作中,Fiddler 一直是最普及的 HTTP 抓包工具之一。但随着 HTTP/2 协议的全面普及,越来越多的开发者遇到了相同的困境:明明配置好了系统代理、信任了根证书,目标站点或 App 的流量却要么只显示一条CONNECT隧道记录、要么内容全是乱码、要么干脆抓不到任何请求。本文就从这个经典问题切入,拆解 HTTP/2 协议的核心特性,分析 Fiddler 抓包失效的根本原因,并系统梳理 HTTP/2 协议逆向的完整方法论。

一、先回到原点:Fiddler 为什么能抓到 HTTP/1.1 的包?

要理解 "抓不到" 的原因,首先要明确 Fiddler 的工作本质。Fiddler 是典型的HTTP 中间人(MITM)代理,它的抓包逻辑建立在 HTTP/1.1 的明文协议特性之上:

  1. 隧道建立 :客户端发起 HTTPS 请求时,先向代理发送CONNECT请求,建立 TCP 隧道;
  2. 证书替换:Fiddler 拦截隧道后,用自己的根证书签发服务端证书,与客户端完成 TLS 握手;同时 Fiddler 作为客户端与真实服务端完成 TLS 握手;
  3. 明文解析:TLS 层解密后,HTTP/1.1 是纯文本格式的报文,Fiddler 可以直接解析请求行、头部、响应体,完成修改、断点、日志等所有操作。

这套逻辑在 HTTP/1.1 时代运行了十几年,几乎所有 HTTP 代理工具都沿用了相同的架构。但 HTTP/2 的出现,从协议底层打破了 "明文报文" 这个前提。

二、为什么 Fiddler 默认抓不到 HTTP/2 流量?

HTTP/2(简称 h2)是 IETF 在 2015 年发布的下一代 HTTP 协议,目前主流浏览器、移动端 OkHttp、Go/Python 等语言的标准库都已默认支持。Fiddler 抓包失效的核心原因,本质是协议格式不兼容 + 默认配置未启用支持,具体可以拆解为三点。

1. 二进制分帧:不再是 "一行一行" 的明文

HTTP/1.1 的报文是 ASCII 明文,按行分隔,人类可读。而 HTTP/2 在应用层和 TCP 之间新增了一层二进制分帧层,所有的请求、响应、头部、数据都被拆分成二进制格式的 "帧(Frame)",比如 HEADERS 帧、DATA 帧、SETTINGS 帧、WINDOW_UPDATE 帧等。

如果 Fiddler 不支持 HTTP/2 解析,即使解密了 TLS 流量,拿到的也只是一串二进制字节流,无法识别出请求方法、URL、头部这些关键信息,表现出来就是乱码或者空白内容。

2. ALPN 协商:偷偷升级的协议

绝大多数 HTTP/2 都运行在 TLS 之上(称为 h2),协议版本不是通过 URL 指定,而是在 TLS 握手的ALPN(应用层协议协商) 扩展字段里完成的。客户端在 TLS Client Hello 里带上h2, http/1.1的列表,服务端选择 h2 并返回,后续就直接用 HTTP/2 通信。

旧版本 Fiddler(4.6 版本以前)在作为中间人握手时,不支持 ALPN 扩展,也不会宣告自己支持 h2。于是客户端和 Fiddler 之间协商成 HTTP/1.1,而 Fiddler 和服务端之间协商成了 HTTP/2------ 这就导致 Fiddler 只能解析客户端侧的明文,却无法解析服务端返回的二进制帧,最终表现为响应异常、或者只能看到 CONNECT 隧道。

而新版 Fiddler 即使支持 ALPN,如果没有手动开启 HTTP/2 解析功能,也只会把 HTTP/2 流量当作二进制隧道转发,不会进行拆解和展示。

3. 多路复用:一个 TCP 连接跑 N 个请求

HTTP/1.1 时代,一个请求对应一个 TCP 连接(或长连接串行),Fiddler 可以按连接区分请求。但 HTTP/2 支持多路复用 ,同一个 TCP 连接上可以并行跑几十个请求,每个请求用不同的Stream ID标识。

如果工具不支持流解析,就无法把二进制帧还原成一个个独立的 HTTP 请求响应,自然也就没法像 HTTP/1.1 那样逐条展示。

三、第一步:让 Fiddler "看懂" HTTP/2

其实从 Fiddler 4.6 版本开始,官方已经内置了 HTTP/2 支持,只是默认没有开启。解决 "抓不到" 的第一步,就是先打开这个开关:

  1. 打开 Fiddler,进入 Tools -> Options -> HTTPS;
  2. 勾选 Enable HTTP/2 support 选项;
  3. 重启 Fiddler,重新抓包。

开启后,Fiddler 会在 TLS 握手的 ALPN 中宣告支持 h2,与客户端、服务端分别建立 HTTP/2 连接,并在内部完成二进制帧的解析与还原。此时再抓 HTTP/2 的站点,就能像 HTTP/1.1 一样看到请求 URL、头部、响应体,也支持断点修改。

但这只是 "入门级" 的解决。开启 HTTP/2 支持后,Fiddler 仍然存在很多局限:

  • 只能展示还原后的 HTTP 语义,看不到底层的帧类型、流 ID、优先级等信息;
  • 对 HPACK 头部压缩的动态表维护不透明,无法分析压缩细节;
  • 对服务器推送(Server Push)、流控等高级特性支持有限;
  • 部分自定义 HTTP/2 实现的客户端会出现兼容问题。

对于深度逆向和反爬对抗而言,只靠 Fiddler 的可视化是远远不够的,我们需要回到协议本身。

四、HTTP/2 逆向的核心难点:和 HTTP/1.1 到底哪里不一样?

做 HTTP/2 逆向,不能只停留在 "能抓到包" 的层面。很多基于 HTTP/2 的反爬机制,恰恰利用了协议的新特性。理解这些差异,是逆向分析的基础。

1. HPACK 头部压缩:不再是明文头

HTTP/1.1 的头部是纯文本,每个请求都要重复携带 Cookie、User-Agent 等大量重复字段。HTTP/2 用HPACK 算法压缩头部,核心是静态表、动态表和霍夫曼编码:

  • 静态表:预定义了 61 个常见头部字段和值,用索引代替;
  • 动态表:连接过程中出现的新头部会被加入动态表,后续只用索引引用;
  • 霍夫曼编码:对字符串字面量进行压缩。

这意味着,头部在传输中是 "索引 + 编码" 的二进制格式,而不是明文。对于逆向来说,动态表的维护状态会影响头部的传输内容,如果模拟请求时不处理 HPACK,直接发送明文头部,很容易被服务端识别为异常客户端。

2. HTTP/2 指纹:比 TLS 指纹更精准的身份标识

近几年反爬体系的一个重要升级,就是从 JA3/TLS 指纹转向了HTTP/2 指纹。因为 HTTP/2 的很多参数是客户端实现决定的,且很难伪造:

  • SETTINGS帧的参数:比如 SETTINGS_MAX_CONCURRENT_STREAMS、SETTINGS_INITIAL_WINDOW_SIZE 等参数的取值,不同客户端(浏览器、OkHttp、curl)差异很大;
  • 帧的发送顺序:比如 SETTINGS、WINDOW_UPDATE、HEADERS 帧的发送先后顺序;
  • 流优先级策略:Stream 的依赖关系、权重分配;
  • 窗口更新的频率和大小。

这些特征组合起来,形成了比 TLS 指纹更稳定的客户端标识。这就是为什么很多时候你绕过了证书验证、模拟了所有请求头,还是被 403 拦截 ------ 问题出在 HTTP/2 的指纹上。

3. 二进制帧的隐式信息

除了请求体和头部,HTTP/2 的帧本身也能携带信息。比如服务端可以通过PING帧探测客户端的响应速度,通过RST_STREAM帧的错误码传递状态,这些在 HTTP/1.1 里都没有对应概念,传统抓包工具也不会重点展示。

五、HTTP/2 逆向的工具链与实战方法

只靠 Fiddler 不足以应对深度逆向,我们需要一套从抓包、解析到模拟的完整工具链。下面按场景介绍最常用的方案。

场景 1:完整解析二进制帧与协议细节 ------Wireshark + SSLKEYLOGFILE

如果需要分析最底层的帧结构、HPACK 细节、ALPN 协商过程,Wireshark 是首选工具。配合 SSL 密钥日志,可以直接解密 TLS 层的 HTTP/2 流量:

  1. 设置环境变量SSLKEYLOGFILE=D:/sslkey.log;
  2. 用支持该环境变量的客户端(Chrome、curl、Python httpx 等)发起请求,密钥会自动写入日志;
  3. Wireshark 中进入 编辑 -> 首选项 -> 协议 -> TLS,在(Pre)-Master-Secret log filename中选择上述日志文件;
  4. 过滤条件输入http2,即可看到所有解析后的帧,包括帧类型、流 ID、HPACK 解码后的头部、窗口更新等所有细节。

这种方法是分析 HTTP/2 指纹、排查协议兼容性问题的终极手段。

场景 2:日常抓包与修改 ------mitmproxy / Charles

除了 Fiddler,另外两款主流代理工具对 HTTP/2 的支持更加成熟:

  • mitmproxy:默认开启 HTTP/2 支持,命令行和 Web 界面都能清晰展示流 ID、帧信息,支持用 Python 脚本自定义处理 HTTP/2 帧,是自动化逆向的首选;
  • Charles :在 Proxy -> SSL Proxying Settings 中启用 HTTP/2,对移动端的兼容性更好,UI 交互更直观。

场景 3:客户端逆向与 Hook------Frida + 网络库 Hook

对于移动端 App 的 HTTP/2 逆向,很多时候问题不在代理,而在客户端的证书绑定、自定义 TLS 库或者自定义 HTTP/2 实现。

以 Android 最常见的 OkHttp 为例,HTTP/2 的实现位于okhttp3.internal.http2包下。通过 Frida HookHttp2Codec、FrameReader、FrameWriter等类的关键方法,可以直接打印出所有收发的帧内容、流 ID、头部信息,完全绕过代理抓包的限制。

如果是底层用 C++ 实现的 HTTP/2 库(比如 nghttp2),则可以 Hook nghttp2_session_send、nghttp2_session_recv等原生函数,直接 dump 二进制帧数据。

场景 4:模拟 HTTP/2 指纹 ------ 自定义客户端

当遇到基于 HTTP/2 指纹的反爬时,普通的 curl、requests 无法修改指纹参数,需要用支持自定义帧参数的 HTTP/2 库:

  • Go 语言:golang.org/x/net/http2 可以深度自定义Server和Transport的 Settings 参数、流控策略;
  • Python:hyper 库、httpx 的底层定制,或者直接用 nghttp2 的 Python 绑定;
  • 最极致的方案是基于 nghttp2 库自己封装客户端,精确控制 SETTINGS 帧的每一个参数、帧发送顺序、窗口更新策略,1:1 还原目标客户端的指纹。

六、常见坑点与排查思路

在 HTTP/2 逆向过程中,有几个高频出现的问题,这里统一给出排查方向:

  1. 开启 Fiddler HTTP/2 后,目标站点报错 / 连接失败 大概率是 Fiddler 的 HTTP/2 实现与服务端不兼容,比如不支持某些 SETTINGS 参数。可以换用 mitmproxy 测试,或者用 Wireshark 对比直连和走代理时的帧差异。
  2. 明文 HTTP/2(h2c)抓不到 部分内部服务会用不带 TLS 的 h2c(HTTP/2 over TCP),Fiddler 默认无法识别。这种情况直接用 Wireshark 抓 TCP 包,过滤http2即可解析。
  3. 能抓到包但请求失败,提示协议错误 检查是否修改了头部后破坏了 HPACK 的动态表状态。HTTP/2 的头部压缩是有状态的,中途修改单个请求的头部可能导致后续请求的解码错误。
  4. 同一个连接的多个请求时序混乱 这是多路复用的正常现象,不要用 HTTP/1.1 的串行思维去理解。按 Stream ID 分组查看,每个 Stream 内部是有序的。

七、结语

HTTP/2 已经成为互联网的主流协议,HTTP/3(QUIC)也在快速普及。对于逆向工程师而言,"Fiddler 抓不到包" 只是第一个门槛 ------ 真正的挑战在于理解协议的底层机制,应对基于协议特性的反爬对抗。

从依赖工具的 "一键抓包",到深入二进制分帧、HPACK、指纹这些底层细节,本质上是从 "使用工具" 到 "理解协议" 的能力升级。而所有的逆向工作,最终都要回归到协议本身的原理上。毕竟,工具总会有不支持的功能,但原理永远不会骗你。

相关推荐
盛世宏博智慧档案1 小时前
一文读懂 PoE+Modbus TCP 温湿度传感器布线规范与故障排查
网络·网络协议·tcp/ip
盛世宏博智慧档案3 小时前
多配电室 VLAN 隔离怎么统一监控?IP 温湿度跨网段采集方案
网络·网络协议·tcp/ip·传感器·温湿度
fthux4 小时前
开源小工具 Who Arrives:看看你的公网 IP、地区、时区和网络
http·开源·github
青瓦梦滋4 小时前
【在线五子棋对战】在线用户
服务器·网络·网络协议
隐擎fox6 小时前
深入网络风控底层:解密 IP 信誉评分模型、ASN 属性判定与多租户原生网络隔离架构
网络·爬虫·网络协议·tcp/ip·架构·跨境电商·指纹浏览器
青瓦梦滋6 小时前
【在线五子棋对战】session
服务器·网络·网络协议