CVE-2019-9514: HTTP/2 Reset Flood 拒绝服务漏洞分析

0x00 漏洞背景与详情

  • CVE 编号:CVE-2019-9514
  • 漏洞名称:HTTP/2 Reset Flood (HTTP/2 重置洪水攻击)
  • 影响协议:HTTP/2 (RFC 7540)
  • 危险等级:高危 (CVSS 7.5)
  • 影响范围:几乎所有主流 HTTP/2 服务端实现,包括 Nginx (1.10.0+), Apache (2.4.17+), Go net/http, Node.js 等。

该漏洞是 2019 年由 Netflix 和 Google 联合披露的 HTTP/2 系列拒绝服务(DoS)漏洞之一。它利用了 HTTP/2 协议的流取消机制,通过持续发送复位帧(RST_STREAM)绕过服务端的并发限制,导致服务端资源耗尽崩溃。

(注:该漏洞是后来 2023 年 CVE-2023-44487 Rapid Reset 的“前辈”,两者的核心思想非常相似,但在帧序列的处理上存在微小差别)

0x01 漏洞原理分析

HTTP/2 协议引入了多路复用(Multiplexing),允许在单个 TCP 连接上并发处理多个请求(流)。为了防止资源耗尽,服务端会设置 SETTINGS_MAX_CONCURRENT_STREAMS 参数(通常为 100)来限制活动中的流数量。

核心逻辑缺陷:

  1. 发起请求:攻击者发送一个 HEADERS 帧(发起一个新请求)。
  2. 立即重置:紧接着发送一个 RST_STREAM 帧。
  3. 计数器绕过:根据协议规范,RST_STREAM 会立即使流进入“关闭”状态,从而立刻释放服务端的并发流配额。
  4. 资源损耗:虽然并发计数器被重置了,但服务端在处理 HEADERS 帧(如 HPACK 头部解压、路由逻辑触发、安全检查等)时已经消耗了不可逆的 CPU 和内存。
  5. 洪水效应:攻击者通过不断循环“请求-重置”,可以在不触发并发流限制的情况下,在单个连接上向服务端灌入海量请求,最终导致 OOM 或 CPU 满载。

0x02 POC (Proof of Concept) 与利用逻辑

攻击者通常使用 Go 或 C++ 编写高性能脚本直接操作 HTTP/2 帧。以下是核心攻击逻辑的 Go 伪代码:

// 基于 golang.org/x/net/http2
func resetFloodAttack(conn net.Conn) {
    framer := http2.NewFramer(conn, conn)
    var streamID uint32 = 1

    for {
        // 1. 发送 HEADERS 帧 (开启新流)
        framer.WriteHeaders(http2.HeadersFrameParam{
            StreamID:      streamID,
            BlockFragment: myHpackEncodedHeaders, // 预先编码好的头部
            EndStream:     true,
            EndHeaders:    true,
        })

        // 2. 立即发送 RST_STREAM 帧 (取消流,释放配额)
        // 错误码使用 CANCEL (8) 或 NO_ERROR (0)
        framer.WriteRSTStream(streamID, http2.ErrCodeCancel)

        // 3. 递增 Stream ID (客户端流ID必须为奇数)
        streamID += 2
        
        // 达到流 ID 上限后需重连 TCP
        if streamID > 2147483647 { break }
    }
}

0x03 高级利用姿势

在实战中,攻击者通过演化手法可以规避早期的防御:

  1. 并发控制绕过 (Concurrency Bypass): 利用“快速重置”特性,使服务端始终认为当前活跃连接数为 0,从而完美绕过所有基于 MAX_CONCURRENT_STREAMS 的防御。
  2. HPACK 压力增强 (HPACK Bombing): 在 HEADERS 帧中构造极其复杂的动态表指令。即使流被重置,服务端在解压和维护 HPACK 状态时的内存开销也无法撤回,极大地加速了内存溢出(OOM)的发生。
  3. 混合协议攻击: 将 Reset Flood 与 Ping Flood (CVE-2019-9512)Settings Flood (CVE-2019-9515) 混合使用。在发送大量的 HEADERSRST_STREAM 的同时插入 PING 帧,迫使服务端进行复杂的确认计算,形成多维度的资源挤兑。
  4. WAF 绕过姿势
    • 延迟重置:不立即重置,而是等待服务端开始读取 Body 或触发后端业务(如数据库查询)后再重置,增加后端资源损耗。
    • 帧交织:在 HEADERSRST 序列中随机插入无效的 DATAWINDOW_UPDATE 帧,干扰 WAF 的流序列检测算法。

0x04 应急排查与日志痕迹分析

1. 资源监控指标

  • CPU 异常:Web 服务进程(如 nginx worker)CPU 占用率飙升至 100%,但服务器带宽入口流量(BPS)并不显著,呈现典型的“低带宽、高请求”特征。

2. 流量抓包分析 (PCAP)

  • 使用 Wireshark 过滤 http2
  • 特征:观察到大量的 HEADERS 帧和 RST_STREAM 帧以 1:1 的比例交替出现,且两个帧的时间戳间隔极短(微秒级)。

3. 日志排查

  • Access Log:普通访问日志可能完全没有记录(因为请求被过早重置,未触发日志生成逻辑),或者出现大量状态码为 499 (Nginx: Client Closed Request) 的记录。
  • Error/Debug Log:如果开启了 HTTP/2 级别的调试日志,会看到密集的 stream <ID> was resetclient canceled stream 报错信息。

0x05 修复与缓解建议

  1. 核心补丁更新
    • Nginx:升级至 1.16.1+1.17.3+。新版本引入了对每连接重置频率的平滑限制机制。
    • Apache:升级至 2.4.41+
    • 各开发语言底层的 HTTP/2 库均需升级至最新补丁。
  2. 配置加固
    • 限制单连接总请求数:在 Nginx 中设置 http2_max_requests(默认 1000),强制频繁重置的连接在达到上限后断开,增加攻击者重建 TCP 连接的开销。
  3. 基础设施保护: 使用具备 HTTP/2 深度检测能力的 DDoS 清洗服务,拦截异常帧序列。

0x06 参考资料