HTTP Request Smuggling 请求走私
参考文章
浅析HTTP走私攻击
SeeBug-协议层的攻击——HTTP请求走私
HTTP 走私漏洞分析
简单介绍
攻击者通过构造特殊结构的请求,干扰网站服务器对请求的处理,从而实现攻击目标
前提知识
注:以下文章中的前端指的是(代理服务器、CDN等)
Persistent Connection:
持久连接,Connection: keep-alive。
比如打开一个网页,我们可以在浏览器控制端看到浏览器发送了许多请求(HTML、图片、css、js),而我们知道每一次发送HTTP请求需要经过 TCP 三次握手,发送完毕又有四次挥手。当单个用户同时需要发送多个请求时,这一点消耗或许微不足道,但当有许多用户同时发起请求的时候,便会给服务器造成很多不必要的消耗。为了解决这一问题,在 HTTP 协议中便新加了 Connection: keep-alive 这一个请求头,当有些请求带着 Connection: close 的话,通信完成之后,服务器会中断 TCP 连接。如此便解决了额外消耗的问题,但是服务器端处理请求的方式仍旧是请求一次响应一次,然后再处理下一个请求,当一个请求发生阻塞时,便会影响后续所有请求,为此 Pipelining 异步技术解决了这一个问题
Pipelining:
能一次处理多个请求,客户端不必等到上一个请求的响应后再发送下一个请求。服务器那边一次可以接收多个请求,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端
但是这样也会带来一个问题————如何区分每一个请求才不会导致混淆————前端与后端必须短时间内对每个数据包的边界大小达成一致。否则,攻击者就可以构造发送一个特殊的数据包发起攻击。那么如何界定数据包边界呢?
有两种方式: Content-Length 、 Transfer-Encoding.
Content-Length:
CL,请求体或者响应体长度(十进制)。字符算一个,CRLF(一个换行)算两个。通常如果 Content-Length 的值比实际长度小,会造成内容被截断;如果比实体内容大,会造成 pending,也就是等待直到超时。
Transfer-Encoding:
TE,其只有一个值 chunked (分块编码)。分块编码相当简单,在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,报文中的实体需要改为用一系列分块来传输。每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的 CRLF(\r\n),也不包括分块数据结尾的 CRLF,但是包括分块中的换行,值算2。最后一个分块长度值必须为 0,对应的分块数据没有内容,表示实体结束。
例如:
POST /langdetect HTTP/1.1
Host: fanyi.baidu.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 93
Transfer-Encoding: chunked
2;逗号后面是注释
qu
3;3表示后面的字符长度为3(十六进制),不算CRLF(\r\n回车换行)
ery
1
=
2
ja
2
ck
0;0表示实体结束
注:根据 RFC 标准,如果接收到的消息同时具有传输编码标头字段和内容长度标头字段,则必须忽略内容长度标头字段,当然也有不遵循标准的例外。
根据标准,当接受到如 Transfer-Encoding: chunked, error 有多个值或者不识别的值时的时候,应该返回 400 错误。但是有一些方法可以绕过
(导致既不返回400错误,又可以使 Transfer-Encoding 标头失效):
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
GET / HTTP/1.1
Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
产生原因
HTTP规范提供了两种不同方式来指定请求的结束位置,它们是 Content-Length 标头和 Transfer-Encoding 标头。当前/后端对数据包边界的校验不一致时,
使得后端将一个恶意的残缺请求需要和下一个正常的请求进行拼接,从而吞并了其他用户的正常请求。如图:
那么前/后端校验不一致有那些情况呢呢呢呢?