Web安全之HTTP请求走私攻击(HTTP Request Smuggling)详解
描述
HTTP请求走私是一种利用HTTP服务器对请求消息解析的差异,通过构造一个模糊的HTTP请求,来干扰请求的处理边界,从而让前端代理服务器与后端源站服务器对“请求的结束位置”和“下一个请求的开始位置”产生不同判断的攻击技术。成功利用可导致请求走私、缓存投毒、权限绕过、窃取用户请求等严重后果。
解题过程与原理详解
核心问题根源:HTTP/1.1允许在单个TCP连接上发送多个请求,协议依靠“Content-Length”和“Transfer-Encoding”等头部来判断每个请求的边界。当前端服务器(如反向代理、CDN、WAF)与后端服务器采用不同的方式解析请求边界时,就会产生解析歧义,攻击者可精心构造一个请求,使得前端和后端看到不同的“请求组合”。
第一步:理解两种确定请求体长度的标准方法
-
Content-Length
Content-Length: 13明确表示请求体长度为13字节。- 服务器读取完请求头后,会严格按照这个长度读取对应字节数的请求体,之后认为当前请求结束,后续数据属于下一个请求。
-
Transfer-Encoding: chunked
- 表示请求体是分块传输的。格式为:
<块大小(十六进制)>\r\n <块数据>\r\n 0\r\n \r\n - 服务器会一块一块地读取,直到遇到一个大小为
0的块,标志请求体结束。
- 表示请求体是分块传输的。格式为:
关键点:HTTP规范规定,如果请求中同时包含Content-Length和Transfer-Encoding,Transfer-Encoding应被优先采用,Content-Length应被忽略。但并非所有服务器都严格遵守此规范,或处理顺序存在差异。
第二步:认识两种经典的走私攻击技术
假设网络拓扑为:客户端 -> 前端服务器 -> 后端服务器。攻击者通过一个TCP连接发送恶意请求。
-
CL.TE走私(前端用
Content-Length,后端用Transfer-Encoding)- 构造请求:
POST /vulnerable-endpoint HTTP/1.1 Host: target.com Content-Length: 6 Transfer-Encoding: chunked 0 G - 前端视角:看到
Content-Length: 6。它会读取6个字节的请求体(即0\r\n\r\nG),之后认为第一个请求结束,将剩余的字符G视为下一个请求的开始。 - 后端视角:看到
Transfer-Encoding: chunked。它开始分块解析:第一块0\r\n表示0字节,接着\r\n,于是认为整个请求体已结束。后面的字符G被当作是下一个请求的第一个字符。 - 结果:后端将
G解析为下一个请求的起始(例如GET /admin HTTP/1.1...的一部分),实现了请求走私。如果这个“走私”的请求能影响其他用户的请求,就形成了攻击。
- 构造请求:
-
TE.CL走私(前端用
Transfer-Encoding,后端用Content-Length)- 构造请求:
POST /vulnerable-endpoint HTTP/1.1 Host: target.com Content-Length: 4 Transfer-Encoding: chunked 5c (这里是92字节的恶意数据,例如“GET /admin HTTP/1.1\r\nHost: target.com\r\n\r\n”) 0 - 前端视角:看到
Transfer-Encoding: chunked。它解析第一块大小为5c(十六进制,即92字节),读取接下来的92字节,然后遇到0\r\n\r\n,认为第一个请求结束。 - 后端视角:忽略了
Transfer-Encoding,只认Content-Length: 4。它只读取请求头后的4个字节(即5c\r\n),就认为第一个请求结束了。后面那92字节的恶意数据,被它当作是下一个请求。 - 结果:走私成功。这个恶意请求(如访问
/admin)会被后端处理,并可能影响到后续连接到此TCP连接的其他用户请求。
- 构造请求:
第三步:扩展与变种技术(TE.TE攻击)
- 场景:当服务器链中,有一个服务器对
Transfer-Encoding头部的处理存在缺陷时(例如,可以被混淆、重写),可以利用这种差异。 - 构造方法:对
Transfer-Encoding头部进行混淆,诱导前后端产生不同解析。Transfer-Encoding: xchunkedTransfer-Encoding : chunked(头部名称后加空格)Transfer-Encoding: chunked
Transfer-Encoding: identity(重复头部)Transfer-Encoding: x, chunked
- 原理:前端服务器可能被某种混淆绕过,从而不采用
chunked解析;而后端服务器则能正确识别chunked,反之亦然。这就在CL.TE和TE.CL之外,创造了新的解析差异点。
第四步:攻击利用场景与危害
- 绕过安全控制:前端WAF、防火墙可能只检查第一个“合法”请求,而将走私的恶意请求(如SQL注入、路径遍历)直接传递给后端应用。
- 劫持用户请求:攻击者先发送一个走私请求,然后让正常用户的请求“紧跟”其后。后端会将用户的请求行和头部,当作走私请求的“请求体”的一部分,导致用户请求被篡改或重定向,进而可能窃取用户Cookie、授权令牌。
- 缓存投毒:走私的请求可能是一个恶意构造的请求,其响应被前端缓存服务器缓存,污染了缓存键,导致其他用户访问时得到恶意内容(如XSS脚本)。
- 权限提升:走私一个访问高权限接口的请求,将其与另一个低权限用户的请求绑定,可能导致后端以高权限处理了该请求。
第五步:检测与防御策略
-
检测:
- 时间差法:发送一个模糊的走私请求,然后紧跟一个正常请求。如果第二个请求的响应延迟或异常,表明可能存在走私漏洞。
- 干扰响应法:如果走私成功,第二个请求可能会得到第一个请求的响应内容。
-
防御(服务器端/开发运维):
- 禁用连接重用:在后端服务器上,对来自前端的连接,处理完一个请求后立即关闭连接。但这会影响性能。
- 使用HTTP/2:HTTP/2是二进制、分帧的协议,有明确的帧边界,天然能防御基于HTTP/1.1的请求走私。尽可能在前端与后端之间使用HTTP/2。
- 规范化请求:前端代理应严格规范化并重新构建发往后端的请求,例如,当存在
Transfer-Encoding: chunked时,强制删除Content-Length头部,并正确计算新的Content-Length。 - 使用同构服务器:确保前端和后端服务器使用同种技术栈和配置,减少解析差异。
- 安全头部:某些WAF或服务器可以配置规则,检测和阻止畸形的
Content-Length或Transfer-Encoding头部。
-
开发注意事项:应用层代码难以直接防御此类攻击,因为漏洞发生在网络基础设施层面。但保持应用框架、服务器、代理的最新版本,可以避免已知的解析器漏洞。