Apache Tomcat HTTP请求走私漏洞(CVE-2021-33037)深入分析与教学指南
漏洞概述
Apache Tomcat在处理HTTP/1.0请求时,对Transfer-Encoding头的解析存在缺陷,导致在与反向代理一起使用时可能出现HTTP请求走私漏洞。该漏洞影响以下版本:
- Apache Tomcat 10.0.0-M1至10.0.6
- Apache Tomcat 9.0.0.M1至9.0.46
- Apache Tomcat 8.5.0至8.5.66
HTTP请求走私基础
HTTP请求走私(HTTP Request Smuggling)是指攻击者通过精心构造的HTTP请求,利用前端代理(如Nginx)和后端服务器(如Tomcat)对HTTP协议解析的差异,使得前端和后端对请求边界的理解不一致,从而导致恶意请求"走私"到后端服务器的处理流程中。
常见HTTP走私类型
- CL不为0的GET请求:GET请求带有非零的Content-Length
- CL-CL:请求包含两个Content-Length头
- CL-TE:请求同时包含Content-Length和Transfer-Encoding头
- TE-CL:请求同时包含Transfer-Encoding和Content-Length头
- TE-TE:请求包含两个Transfer-Encoding头
CVE-2021-33037漏洞特殊性
Tomcat的这个漏洞与上述常见类型都不同,是通过HTTP版本和Transfer-Encoding头的特殊组合造成的。
漏洞核心问题
当客户端声明只接受HTTP/1.0响应时,Tomcat会错误地忽略Transfer-Encoding头,同时:
- Tomcat会尊重identity编码
- 不能确保分块编码(如果存在)是最终编码
漏洞复现
测试环境
- Tomcat版本:9.0.35
- 后端代码示例:
request.getParameter("a");
测试请求
HTTP/1.1请求:
POST /test HTTP/1.1
Host: example.com
Transfer-Encoding: chunked
Content-Type: application/x-www-form-urlencoded
3
a=b
0
Tomcat会正常解析Transfer-Encoding: chunked,参数a的值为"b"。
HTTP/1.0请求:
POST /test HTTP/1.0
Host: example.com
Transfer-Encoding: chunked
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
3
a=b
0
Tomcat会忽略Transfer-Encoding头,按照Content-Length解析,导致参数a的值为"b\r\n0\r\n"。
漏洞代码分析
Tomcat的HTTP协议解析主要在org.apache.coyote.http11.Http11Processor类的prepareRequest方法中实现。
HTTP/1.1处理流程
- 处理Transfer-Encoding头
- 将TE取值作为encoding增加到inputFilter中
- 对于多个TE值,以chunked结束
- 如果TE为identity则跳过处理
- 如果TE为chunked则设置相应过滤器
- 其他有效TE值调用addActiveFilter函数
- 无效TE值返回501错误
HTTP/1.0处理流程
关键代码判断:
if (http11 || inputBuffer.isChunkingAllowed()) {
// 处理Transfer-Encoding
} else {
// 跳过Transfer-Encoding处理
}
在HTTP/1.0协议下,Tomcat会跳过Transfer-Encoding头的处理,直接进入Content-Length的解析,默认激活identity编码。
实际攻击场景分析
搭建环境:Ubuntu 16.04 + Nginx 1.14.0 + Tomcat 8.5.45
发现Nginx对HTTP/1.0请求中的Transfer-Encoding也会进行解析,而Tomcat不能正确解析HTTP/1.0中的chunked数据,这就形成了TE-CL类型的HTTP走私漏洞。
RFC规范分析
根据RFC 7230第3.3.1节:
- Transfer-Encoding是在HTTP/1.1中添加的功能
- HTTP/1.0实现应忽略Transfer-Encoding
- 客户端不应发送包含Transfer-Encoding的请求,除非知道服务器可以处理HTTP/1.1或更高版本的请求
Tomcat开发者可能误解了规范,直接将HTTP/1.0协议设置为不支持Transfer-Encoding,即使它实现了HTTP/1.1的Transfer-Encoding功能。
漏洞修复建议
-
升级到不受影响的Tomcat版本:
- Tomcat 10.0.7+
- Tomcat 9.0.47+
- Tomcat 8.5.67+
-
配置反向代理确保HTTP协议版本一致性
-
在无法升级的情况下,限制只接受HTTP/1.1请求
防御措施
-
前端代理配置:
- 强制所有后端连接使用HTTP/1.1
- 规范化请求头,移除冗余的Transfer-Encoding或Content-Length
-
后端服务器配置:
- 拒绝包含Transfer-Encoding头的HTTP/1.0请求
- 严格验证请求格式
-
应用层防御:
- 实现请求验证中间件
- 监控异常请求模式
总结
CVE-2021-33037展示了协议实现不一致带来的安全隐患,即使在遵循RFC规范的情况下,不同组件对协议细节的实现差异也可能导致严重的安全问题。这提醒我们在构建多层Web架构时,必须确保各组件对协议的处理方式一致,并对边界条件进行充分测试。