谷歌:HTTP/2“快速重置”DDoS 攻击


谷歌的云客户已成为基于 HTTP/2 的新型 DDoS 攻击的目标,攻击在 8 月份达到顶峰,最大的攻击每秒超过 3.98 亿个请求。


HTTP/1.1:每次连接 1 个请求
在 HTTP/1.1 中,每个请求都是串行处理的。服务器将读取请求、处理它、写入响应,然后才读取并处理下一个请求。实际上,这意味着可以通过单个连接发送的请求的速率是每次往返一个请求,其中往返包括网络延迟、代理处理时间和后端请求处理时间。

HTTP/2 多路复用:每个连接有 100 个请求
使用 HTTP/2,客户端可以在单个 TCP 连接上打开多个并发流,每个流对应一个 HTTP 请求。理论上,并发打开流的最大数量是由服务器控制的,但实际上,客户端每个请求可以打开 100 个流,并且服务器并行处理这些请求。需要注意的是,服务器限制不能单方面调整。

HTTP/2 快速重置:每个连接无限期请求
HTTP/2 协议允许客户端向服务器指示应通过发送 RST_STREAM 帧来取消先前的流。该协议不要求客户端和服务器以任何方式协调取消,客户端可以单方面这样做。客户端还可以假设,当服务器收到 RST_STREAM 帧时,在处理来自该 TCP 连接的任何其他数据之前,取消将立即生效。

这种攻击称为快速重置Rapid Reset,因为它依赖于端点在发送请求帧后立即发送 RST_STREAM 帧的能力,这使得另一个端点开始工作,然后快速重置请求。请求被取消,但 HTTP/2 连接保持打开状态。

HTTP/2“快速重置”DDoS 攻击
HTTP/2 快速重置攻击很简单:客户端像标准 HTTP/2 攻击一样一次打开大量流,而不是等待服务器或代理对每个请求流的响应,客户端立即取消每个请求。

每个连接有无限数量的正在运行的请求。通过显式取消请求,攻击者永远不会超过并发打开流的数量限制。进行中请求的数量不再取决于往返时间 (RTT),而仅取决于可用网络带宽。

攻击者获得的另一个优势是,在创建请求后立即显式取消请求意味着反向代理服务器不会发送对任何请求的响应。在写入响应之前取消请求会减少下行链路(攻击者的服务器/代理)带宽。

HTTP/2 快速重置攻击变种
在最初的 DDoS 攻击发生后的几周内,谷歌发现了一些快速重置攻击变体。这些变体通常不如初始版本有效,但仍可能比标准 HTTP/2 DDoS 攻击更有效。

  • 第一个变体不会立即取消流,而是立即打开一批流,等待一段时间,然后取消这些流,然后立即打开另一大批新流。此攻击可能会绕过仅基于入站 RST_STREAM 帧速率的缓解措施(例如在关闭连接之前允许每秒最多 100 个 RST_STREAM)。
  • 第二种变体完全取消了流,而是乐观地尝试打开比服务器宣传的更多的并发流。与标准 HTTP/2 DDoS 攻击相比,这种方法的好处是客户端可以始终保持请求管道满载,并消除客户端代理 RTT 作为瓶颈。如果请求是针对 HTTP/2 服务器立即响应的资源,它还可以消除代理服务器 RTT 作为瓶颈。

多方面的缓解方法
谷歌认为认为没有简单办法可以有效缓解此类攻击。

需要在检测到滥用行为时需要关闭整个 TCP 连接:
HTTP/2 使用 GOAWAY 帧类型提供对关闭连接的内置支持。RFC 定义了一个优雅地关闭连接的过程,该过程涉及首先发送一个不限制打开新流的信息性 GOAWAY,然后在一个往返中发送另一个禁止打开其他流的往返。

然而,这种优雅的 GOAWAY 过程通常不是以对恶意客户端具有鲁棒性的方式实现的。这种形式的缓解措施使连接在很长一段时间内容易受到快速重置攻击,因此不应用于构建缓解措施,因为它不会阻止入站请求。相反,应该设置 GOAWAY 以立即限制流创建。

那么,最重要的是需要确定哪些连接是滥用:
客户端取消请求本质上并不是滥用行为,该功能存在于 HTTP/2 协议中以帮助更好地管理请求处理。典型情况是,由于用户离开页面,浏览器不再需要它所请求的资源。

针对这种攻击媒介的缓解措施可以采取多种形式,但主要集中在跟踪连接统计数据并使用各种信号和业务逻辑来确定每个连接的有用程度。例如,如果某个连接有超过 100 个请求,其中超过 50% 的给定请求被取消,则它可能是缓解响应的候选者。

为了缓解此攻击的非取消变体,我们建议 HTTP/2 服务器应关闭超出并发流限制的连接。

微软补丁
Microsoft 安全通报 CVE-2023-44487:.NET 拒绝服务漏洞

Nginx HTTP/2 漏洞 CVE-2023-44487
要完全缓解此问题或显着降低 DoS 攻击的效率,请使用以下建议:

  • 保留 keepalive_requests 的建议设置(“keepalive_requests 1000;”)
  • 保留 http2_max_concurrent_streams 的建议设置(“http2_max_concurrent_streams 128;”)
  • 使用 limit_conn 和 limit_req 配置合理的限制(取决于可以允许单个客户端的负载量):

map $http2 $v1ip {
    default "";
   
""  $binary_remote_addr;
}
map $http2 $v2ip {
    default $binary_remote_addr;
   
"" "";
}

limit_conn_zone $v1ip zone=v1ips:10m;
limit_conn v1ips 10;

limit_conn_zone $v2ip zone=v2ips:10m;
limit_conn v2ips 125;