前言
在2016年的DEF CON 24上 @regilero 发布了名为Hiding Wookiees in HTTP 的报告
视频连接
前段时间做题正好遇到了http请求走私 这里便总结一下
http走私原理
在HTTP 1.0及其以前版本的协议中,在每次进行交互的时候,C/S两端都需要进行TCP的三次握手链接。而如今的web页面大部分主要还是由大量静态资源所组成。如果依然按照HTTP 1.0及其以前版本的协议设计,会导致服务器大量的负载被浪费。于是在HTTP 1.1中,增加了Keep-Alive、Pipeline技术。
Keep-Alive
所谓Keep-Alive,就是在HTTP请求中增加一个特殊的请求头Connection: Keep-Alive,告诉服务器,接收完这次HTTP请求后,不要关闭TCP链接,后面对相同目标服务器的HTTP请求,重用这一个TCP链接,这样只需要进行一次TCP握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。当然,这个特性在HTTP1.1中是默认开启的。
Pipeline
而在Keep-Alive中后续又有了Pipeline机制,这样客户端就可以像流水线一样不用等待某个包的响应而持续的向服务器发包。而服务器也会遵循先进先出原则对客户端请求进行响应。如今,浏览器默认是不启用 Pipeline 的,但是一般的服务器都提供了对 Pipleline 的支持。
当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。
CL-CL
在RFC7230的第3.3.3节中的第四条中,规定当服务器收到的请求中包含两个Content-Length,而且两者的值不同时,需要返回400错误。
但是总有服务器不会严格的实现该规范,假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400错误,但是中间代理服务器按照第一个Content-Length的值对请求进行处理,而后端源站服务器按照第二个Content-Length的值进行处理。
POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 8\r\n
Content-Length: 7\r\n
hello\r\n
you
ou
会被写到下一个包中 前提是Connection:keep-alive
CL-TE
所谓CL-TE,就是当收到存在两个请求头的请求包时,前端代理服务器只处理Content-Length这一请求头,而后端服务器会遵守RFC2616的规定,忽略掉Content-Length,处理Transfer-Encoding这一请求头。
chunk传输数据格式如下,其中size的值由16进制表示。
Content-Length:6
Transfer-Encoding:chunked
f\r\n
\r\n
y
前端代理服务器认为这是一个完整的数据包 正好长度为6
but chunked认为两个\r\n就已经结束了 于是 y就被留到了下一个数据包中
下一个数据包就会拼接成
yPOST / HTTP/1.1\r\n
...
TE-CL
Content-Length: 4\r\n
Transfer-Encoding: chunked\r\n
\r\n
py\r\n
yPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n
所谓TE-CL,就是当收到存在两个请求头的请求包时,前端代理服务器处理Transfer-Encoding这一请求头,而后端服务器处理Content-Length请求头。
前端服务器处理Transfer-Encoding 只能读到0\r\n\r\n 此时前端仍然认为这是一个完整的请求
于是便发送给后端 但是后端只能读到py\r\n 后面的数据便构成了下一个请求
yPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n
总结
如果网络环境中,WAF部署在前端服务器实现安全控制,只有被允许的请求才能转发给后端服务器。
则可以利用http请求走私进行绕过