CRLF与HTTP1.1的长连接
http1.1 ( keep-alive) 长连接
短连接有两个比较大的问题:创建新连接耗费的时间尤为明显,另外 TCP 连接的性能只有在该连接被使用一段时间后(热连接)才能得到改善。为了缓解这些问题,长连接的概念便被设计出来了,甚至在 HTTP/1.1 之前。或者,这被称之为一个 keep-alive 连接。
简单理解,HTTP协议是tcp协议,为了提高效率节省时间,设计了一个客户端和服务端之间的长连接,在实现的时候,客户端实现一个长连接池进行管理,判断请求的服务端在池子中的时候,就直接取出来。省得重新连接浪费时间了。
http1.1的请求的header头里,都会带一个keep-alive的头,就是默认都是长连接。
长连接在网关、反向代理
现在大企业的服务一般都有这些东西,用户的浏览器的http请求到实现业务的主机,中间可能都会经过几层,这里假设是一层网关。
在这种情况下,用户的http请求(浏览器client1)到网关服务器,网关服务器(网关http请求client2)到业务服务器。所以这里就有两个http client。
这里出问题就出现在这第二个client,业务服务器是固定的,网关服务器是固定的,所以他们之间的连接一直都是长连接,这里网关也是一个长连接池管理,在不停的复用长连接。
CRLF + 长连接
CRLF可以RESPONSE注入响应头的。假设业务的代码存在CRLF漏洞,那注入的响应头首先就返回到网关,然后再返回到用户。
HTTP/1.1 协议是应用层协议,它运行在 TCP 之上:
HTTP 请求和响应数据 是通过 TCP 的字节流传输的。
所以一个 HTTP 请求/响应实际上是一串有格式的字节流(例如 headers + body)。
由于 TCP 是字节流,HTTP/1.1 需要通过一些方式告诉对方:
哪里是头部的结束(通常通过 \r\n\r\n)
body 有多长(通过 Content-Length 或 Transfer-Encoding: chunked)
首先要理解流这个概念,复用长连接时,可以理解网关在处理一条条数据流长河。把这个长河分成一小段一小段,就是一个一个http请求的response响应。
那怎么分呢?
一般通过Content-Length来分,目前我看到的实现都是通过Content-Length。Response的Content-Length如果是5,就是在告诉网关的client,这一段读5个长度的body就行了,这些就是请求A的响应。
如果实际body的长度是10但是CRLF设置成5呢?那剩下的5个长度的就是下一个请求B的返回。
但是处理的时候剩下的数据格式不像一个http响应,那就处理报错,请求B的响应那就会返回报错502之类的。
如果能控制剩下的5个长度的body能够满足http响应的格式呢?Ok那你就能控制请求B的response。
除了服务端的Content-Length,还可能会和客户端的设置有关系,比如客户端会设置一个读取长度10K,那就是固定读个10k,如果响应长度小于10K,ok全部读完那就没问题,但是如果大于10k,那还是会有数据残留到下一个http响应。
所以,CRLF能实现什么效果呢,投毒下一个响应,如果payload控制得好,可以完全打乱响应顺序实现,实现真正的已读乱回。