QPACK 放大攻击:HTTP/3 服务器被单个 UDP 连接压垮

2026 年 10 月 20 日,安全公司 FoxIO 公开了名为 Header Accordions 的研究,指出 HTTP/3 所用头部压缩方案 QPACK 存在一类内存放大缺陷:未认证的远程客户端只需发一个极小的 HEADERS 帧,就能让服务器分配数十倍到数千倍于报文体积的内存。测试的 10 个实现中有 7 个受影响,细节与 PoC 已公开。

事件概述

HTTP/3 跑在 QUIC/UDP 之上,头部用 QPACK 压缩:常见字段压成极小索引,重复字段可指向共享表。这省了带宽,也让一个很小的帧足以描述海量头部。FoxIO 在为自己的主动 TLS 扫描器 JA4Scan 增加 QUIC 支持时发现了该问题,思路与 2025 年的 HTTP/2 MadeYouReset 同源:协议本身没问题,出在各实现如何落实安全上限。

技术细节

RFC 9114 要求按解码后的体积限制头部,且每个字段额外计 32 字节开销。受影响的实现主要在四种做法上出错:只限制压缩后体积、先全部解压再检查、漏算 32 字节开销、完全不限制。

攻击有两种变体:一是往一个帧里塞入海量极小的互不相同的头部;二是先插入一个超大表项再反复引用,让每个微小引用都强制完整复制一次。FoxIO 称「一个小的 HEADERS 帧可以膨胀成数十万个内存中的头部对象」。

# 受影响实现与修复版本(截至 2026-10-20)
quic-go            0.57.0        CVE-2025-64702  CVSS 5.3
Cloudflare quiche  0.29.3        CVE-2026-12523  CVSS 7.5
lsquic             4.9.0         无 CVE,放大 600-1800 倍
Wireshark          4.6.2/4.4.12  CVE-2025-13945  CVSS 5.5
# 尚未修复
Bun 1.4.3 / h3 (hyperium) / aioquic 与 mitmproxy

各实现失效方式不同:quic-go 只限制压缩帧大小,实际保留约 15 倍编码体积;quiche 漏算 32 字节开销并为始终不抵达的帧预分配缓冲;lsquic 被 FoxIO 称为「挖得最深」;Bun 移除内置上限,约 4,000 倍放大,另有整数溢出可让进程锁死在 100% CPU 且无法自行恢复。Wireshark 属另一类,是解密流量时解析器崩溃,不是网络可达的服务端漏洞。

影响评估

quic-go 是 Caddy、Traefik、cloudflared 的底层依赖,风险不止于直接引用该库的项目,还要看终端产品实际打包的版本。单个 UDP 连接即可打满内存或钉死 CPU,属纯可用性打击,无需任何凭据。

更难处理的是防护盲区:HTTP/3 走 UDP,许多只做 TCP 状态检查的防火墙与 DDoS 清洗设备不解析 QPACK,前置防护容易形同虚设。目前无在野利用报告,也未进 KEV,但有公开复现代码,风险窗口正在缩短。

修复建议

  • 升级到上表修复版本;只改前端版本号没用,须确认每个 HTTP/3 端点背后真正加载的库版本。
  • 暂无法升级时:不要把 Bun 上的 HTTP/3 服务暴露到公网;mitmproxy 加 --set http3=false;h3 crate 设置合理的 max_field_section_size。
  • 在边缘层对 UDP 443 做速率与并发连接限制,并对 QUIC 做协议感知检测,不只按源 IP 计数。
  • 监控异常:单个连接的内存与 CPU 陡增、工作进程崩溃重启,是最直接的信号。

IIS、Envoy、ngtcp2/nghttp3 与 Google 的 quiche 不受影响。

参考来源