文章总结: BlackHatUSA2026发布的研究展示如何利用HTTP/3的QPACK与Priority机制将竞态条件攻击从概率性变为确定性,实证成功率最高96.4%。攻击通过控制代理内存中的请求调度顺序实现精确时序对齐,影响范围包括仅支持HTTP/1.1的后端。防御建议包括禁用QPACK动态表、使用PostgreSQL及显式行锁、将状态参数从Header移至Body。 综合评分: 88 文章分类: WEB安全,漏洞分析,渗透测试,红队,安全建设
从碰运气到确定性:HTTP/3 竞态条件攻击的范式转变
原创
AIxSec69 AIxSec69
AIxSec69
2026年9月4日 18:44 美国
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
从碰运气到确定性:HTTP/3 竞态条件攻击的范式转变
来源:Black Hat USA 2026 Briefings(8 月 6 日)
标题:Chaos by Design: The Death of Stochastic Race Conditions in HTTP/3
作者:Efstratios Chatzoglou(University of the Aegean, Greece)
适合读者:Web 安全研究员、应用安全工程师、基础设施安全运维
简介:传统竞态条件攻击的最大痛点是什么?不可控。网络抖动、代理缓冲、后端调度,任何一个环节的随机性都能让精心构造的请求对撞功亏一篑。Chatzoglou 的研究把这个前提推翻了:利用 HTTP/3 的 QPACK(RFC 9204)和 Priority(RFC 9218)原生机制,把竞态条件从概率游戏变成了确定性攻击,实证成功率最高 96.4%。
◆ ◆ ◆
打竞态条件的人都知道那种感觉。Burp Suite 的 Turbo Intruder 跑了几千个请求,偶尔命中一次。复现?换个网络环境可能就没了。这不是技术不行。竞态条件天生依赖时序对齐,而网络是最不可控的介质。
Efstratios Chatzoglou 在 Black Hat USA 2026 的演讲 “Chaos by Design” 做了一件事:把时序控制从网络线缆搬进了服务器本地内存。他提出的 Server-Side Race Orchestration(SSRO)和 Temporal Hijacking,利用的是 HTTP/3 自己的协议机制。
不是漏洞。是设计特性被武器化。
先理解为什么 HTTP/3 制造了新机会
HTTP/3 跑在 QUIC 上,QUIC 跑在 UDP 上。和 HTTP/2 over TCP 的架构差异很大。
▲ HTTP/3 优先级扩展(RFC 9218):边缘代理调度并发流的机制(来源:Black Hat USA 2026 Slides)
上图把这层关系讲清楚了。三个变化:
第一,QUIC 在传输层就干掉了 Head-of-Line blocking。TCP 丢一个包整个连接卡住,QUIC 的每个 stream 独立传输,丢包只影响那一个 stream。
第二,每个 HTTP/3 请求是 QUIC 连接里的一个独立逻辑流。多个请求共享同一个加密连接,但各自为政。
第三,边缘代理(NGINX、Envoy、HAProxy)必须用内部的优先级调度器来处理这些并发流。调度决策发生在代理进程的内存里,不在网络上。
第四条是这个研究的发现:这个调度依赖关系在服务器内存里创建了一个可以被外部精确控制的排队机制。
通俗讲:你不再需要”碰运气”让两个请求同时在网络上到达。你只需要构造好请求,让代理自己的调度器在内存里把它们排好队,然后一次性释放。
Temporal Hijacking:用 RFC 9218 优先级劫持调度队列
HTTP/3 有一个叫 Priority 的扩展规范(RFC 9218)。它的本意是让客户端告诉服务器”这个资源比那个更重要”,帮助服务器合理安排带宽。
Chatzoglou 发现了四种武器化方式:
▲ Temporal Hijacking:武器化 urgency(来源:Black Hat USA 2026 Slides)
Proxy Buffering Hold。 发送 header-only 的请求状态,让代理预留到后端的 socket 通道。代理以为请求要来了,分配了资源等着。但请求体故意不发送,代理的解析状态机就卡在半路上。
RFC 9218 Urgency 注入。 给后发送的请求打上 u=0(最高 urgency),给先发送的请求打上 u=7(最低 urgency)。代理的调度器看到 u=0 的请求,会把它插队到 u=7 前面,哪怕 u=7 的请求先到了几百毫秒。内存队列里的顺序被重排了。
PRIORITY_UPDATE 帧。 QUIC/TLS 握手完成后,mid-flight 发送 PRIORITY_UPDATE 帧动态改变流优先级。前面的请求已经进队列了,突然被后面的请求超车。
Legacy Tree Logic。 70% 的现实 Web 服务器仍然支持 RFC 7540(HTTP/2 的优先级树)。利用这种遗留的权重计算逻辑,可以制造复杂的调度计算开销,人为拉长某些请求的处理时间。
四个技术加在一起的效果:攻击者可以精确控制代理内存中请求的处理顺序和时机。网络传输的毫秒级不确定性被降到了微秒级。
QPACK 怎么被反着用
HTTP/2 的头部压缩叫 HPACK(RFC 7541)。它跑在 TCP 上,要求严格有序传输。丢一个包,整个压缩状态就卡住了。
HTTP/3 的头部压缩叫 QPACK(RFC 9204)。设计目标就是解决这个问题:支持乱序传输,引入异步 Header 解码机制。动态表有独立的状态跟踪,接收方不需要按顺序解码。
▲ QPACK 的 Required Insert Count(RIC)机制:让请求在代理内存中滞留的 “waiting room”(来源:Black Hat USA 2026 Slides)
QPACK 里有一个叫 Required Insert Count(RIC)的机制。简单说:如果一个 Header block 引用了解码器还没确认的动态表条目,这个 stream 必须阻塞。请求在代理内存里停住,完全解析完了,但就是不被分发到后端。
这个机制本意是防止解码错误。但 Chatzoglou 发现了它的另一个用法:故意制造 RIC 不匹配,让请求在代理内存里排队等待。
他把这叫做”waiting room 机制”。请求不是被丢弃,不是被拒绝,而是被精确地控制在代理内存中滞留。一旦 RIC 条件满足(比如发送了解码器需要的动态表条目),所有阻塞的 stream 同时释放。
同时释放意味着什么?所有请求在同一个微秒窗口内到达后端。竞态条件从”希望同时到达”变成了”确实同时到达”。
SSRO 五种打法,96.4% 不是吹的
演讲中给出了五种 SSRO 变体的实证数据:
| 变体 | 组合 | 目标 | 成功率 |
|——|——|——|——–|
| Var 1: QPACK HoL Block | Envoy + Go/.NET/FastAPI | Double Spend | 96.4% |
| Var 2: Dynamic Table Saturation | NGINX + Spring/LSPHP | State Inversion | 90.0% |
| Var 3: Cross-Protocol | HAProxy + 所有运行时 | Limit Overrun | 16.4x 乘数 |
| Var 5: QPACK Block + Priority | HAProxy + Go/FastAPI | Double Spend | 95.0% |
Var 2 的 CV(变异系数)只有 0.03。在统计学里,CV 低于 0.1 通常意味着”几乎完美可预测”。这不是”偶尔能成功”,是”几乎每次都成功”。
还有一个细节值得单独说:Header 参数比 Body 参数更容易被利用。 原因是代理边缘把 Header 当作原子块解析,内部调度器即时分发。如果状态变更参数(user_id、amount、权限标记)放在 Header 里,传输层的同步就直接映射到了应用层执行。Body 里的 JSON 还要过一次解析器,多了一层抖动。这个发现对做安全评审的人有直接价值。审计代码时,Header 里的可变参数应该比 Body 里的受到更多关注。
你以为后端跑 HTTP/1.1 就安全了?
演讲里有一段让我印象很深。他说开发者经常有一个幻觉:我的后端只支持 HTTP/1.1,没有 HTTP/3 的多路复用,所以竞态条件攻击对我没威胁。
错了。
边缘代理(负载均衡器、反向代理)充当了一个”去抖动器”。它从 WAN 侧接收碎片化、高抖动的 HTTP/3 流,在本地 RAM 里用 QPACK 和 Priority 机制把它们整理好。然后瞬间把这些已对齐的请求映射到并行的 HTTP/1.1 TCP 连接上,走的是超低延迟的云 LAN。
结果是:攻击者不需要直接和后端 HTTP/1.1 通信。他只需要和前面的代理通信。代理帮他做了所有”对齐”工作。Chatzoglou 把这个叫做”Memory-to-Socket Railgun”。
这个结论把传统的威胁建模范围彻底打穿了。受影响的不只是跑 HTTP/3 全栈的新系统。所有挂在了支持 H3 的 LB 后面的传统企业后端,不管跑的是什么协议,都在射程内。
厂商不修,说”这是按设计工作的”
演讲者通过 CERT/CC 走了协调披露流程。厂商的回应是:流优先级相关的行为是”working as intended”。
这不是一个漏洞,是一组协议机制的武器化利用。QPACK 的 RIC 阻塞、RFC 9218 的 urgency 调度、PRIORITY_UPDATE 帧的动态优先级。每一个单独看都确实是”by design”。但组合起来,就构成了一个可以精确控制竞态时序的攻击系统。
这就尴尬了。你没法让 QPACK 不支持乱序传输,那本来就是它要解决的问题。你也没法让 RFC 9218 不支持 urgency,那是它的基本功能。修一个要动协议的根本机制。
现在能做什么
演讲给出了三层建议:
代理层。 如果你的边缘代理不需要 QPACK 动态表功能,直接把 QPACK\_MAX\_TABLE\_CAPACITY 设为 0,把 QPACK\_BLOCKED\_STREAMS 设为 0。这会关掉动态表压缩和流阻塞机制,代价是压缩效率下降。但对于不需要极致性能压缩的场景,这个代价可以接受。
数据库层。 这个研究里有一个数据非常有意思:PostgreSQL 的防御效果远超 MySQL。同样的攻击场景,MySQL 允许最多 16.4 倍的超限操作,PostgreSQL 把违规限制在 1.0 倍。原因是 PostgreSQL 的 MVCC 实现更严格。另外演讲强调了显式悲观行锁(SELECT FOR UPDATE)和 SERIALIZABLE 隔离级别的必要性。分布式环境还要上真正的分布式锁(像 Redlock),单机 Redis 的原子执行保证不够。
应用层。 审计状态变更参数的位置。Header 里的参数比 Body 里的更容易被竞态利用。如果你在 Header 里传 user_id 或操作标记,考虑挪到 Body。这不是根本解决方案,但能增加攻击者的利用难度。
边界
这项研究的前提假设是攻击者可以向目标发送合法的 HTTP/3 请求(网络可达 + TLS 握手完成)。不是远程 0-click。竞态条件的业务影响取决于具体应用的逻辑。Double Spend、State Inversion、Limit Overrun 的后果各不相同。
TimeOrch 是学术研究工具,已经开源在 GitHub(github.com/efchatz/timeorch)。它不是”装好就能打”的武器,需要理解协议机制才能用起来。
另外要说清楚:SSRO 不是漏洞利用,是协议机制的系统性武器化。它暴露的问题不在某一款产品的代码里,而在协议设计本身的假设中。HTTP/3 假设客户端是善意的,但攻击者不是。
原文链接:https://www.blackhat.com/us-26/briefings/schedule/#chaos-by-design-the-death-of-stochastic-race-conditions-in-http-3-53640
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:AIxSec69 AIxSec69 AIxSec69《从碰运气到确定性:HTTP/3 竞态条件攻击的范式转变》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论