WebScocket简析
前几天渗透某个站的时候发现这个站用burp抓包会成乱码,我以为是我的burp出现了问题,仔细研究后发现这个站用了WebSocket协议,与HTTP协议既有联系又有区别。经过学习,WebSocket协议会不会成为下一个流行的安全协议呢?
注意:以下内容整理于RFC6455文档,感谢HJava的翻译
What is WebSocket?
WebSocket是一种基于TCP协议,复用HTTP协议的全双工的网络通信技术,具体的RFC定义请阅读RFC6455文档。通过将HTTP协议升级到WebSocket协议后,WebSocket相比较HTTP协议的优点有:支持了实时双向通信、更小的控制开销、支持扩展、支持文本和二进制数据、无同源限制。
How to handshake?
因为WebSocket复用了HTTP协议,所以WebSocket也是通过HTTP协议实现握手的,实现方式为协商协议升级,协议升级成功后,所有数据通过WebSocket协议传输。
Request
客户端通过浏览器对WebSocket服务端发起HTTP请求,客户端通过该HTTP请求与服务端协商升级到WebSocket协议。下面的请求包是一个真实环境下的HTTP升级到WebSocket的协商请求头,首先强调一点,HTTP升级到WebSocket必须使用GET
请求。相信任何人都能发现该HTTP请求相比较其他HTTP请求多出了Sec-WebSocket-Version
、Sec-WebSocket-Key
、Upgrade
、Sec-WebSocket-Extensions
请求头字段,我们只需要关注前3种请求头字段即可,第四种请求头字段为扩展。下表详细解释了HTTP升级到WebSocket协议需要的请求头字段含义:
请求头字段 | 含义 |
---|---|
Connection:Upgrade | 表示该HTTP请求为协议升级请求 |
Upgrade:websocket | 表示HTTP协议升级到WebSocket协议 |
Sec-WebSocket-Version: 13 | 表示WebSocket协议版本 |
Sec-WebSocket-Key: 1mJ7j65K03/x4qTLgm1Sjw== | 客户端生成一个16字节的base64编码的随机数 |
GET / HTTP/1.1
Host: xxx.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://xxx.com
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: 1mJ7j65K03/x4qTLgm1Sjw==
Connection: keep-alive, Upgrade
Cookie: 123
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Response
服务端在接收到HTTP升级WebSocket请求后会返回状态码为101
表示协议升级成功,下面的响应包是一个真实环境下的HTTP升级到WebSocket的协商响应包,其中包含了Upgrade
、Sec-WebSocket-Accept
两个关键响应头字段,其中Sec-WebSocket-Accept
是根据客户端的请求头中的Sec-WebSocket-Key
计算而来。
计算的方式是,将请求头中的Sec-WebSocket-Key
与服务端已配置好的密钥拼接做SHA1摘要,转换成base64。其中服务端配置的密钥形似258EAFA5-E914-47DA-95CA-C5AB0DC85B11
HTTP/1.1 101 Switching Protocols
Server: nginx
Date: Tue, 13 Jul 2021 06:47:37 GMT
Connection: upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 3xuGoaKWflZ2lv2NNpvTTUqsYjg=
基础帧协议
下图是WebScoket数据帧的基础格式
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 80 1
+-+-+-+-+-------+-+----------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended paylolength |
|I|S|S|S| (4) |A| (7) | (64) |
|N|V|V|V| |S| | (if payload len==1127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - -- +
| Extended payload length continued, if payload len 127 |
+ - - - - - - - - - - - - - -+-------------------------------+
| |Masking-key, if MASK set 1 |
+----------------------------+-------------------------------+
| Masking-key (continued) | PayloData |
+-------------------------------- - - - - - - - - - - - - -- +
: Payload Data continued. :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -+
| Payload Data continued. |
+------------------------------------------------------------+
详细解释如下:
帧 | 大小 | 含义 |
---|---|---|
FIN | 1bit | 表示这是消息的最后一个片段。 |
RSV1、RSV2、RSV3 | 各1bit | 必须设置为0,除非扩展了非0值含义的扩展。如果收到了一个非0值且没有扩展的含义,服务端必须断开WebSocket |
opcode | 4bit | 定义“有效负载数据”的解释。如果收到一个位置的操作码,服务端必须断开WebSocket连接。如下的值是定义过的: •%x0:表示一个延续帧,当opcode为0时,表示本次数据传输采用了数据分片,当前收到的数据帧为其中一个数据分片。 •%x1:表示这是一个文本帧 •%x2:表示这是一个二进制帧 •%x3-7:保留的操作代码,用于后续定义的非控制帧。 •%x8:表示连接断开。 •%x9:表示这是一个ping操作。 •%xA:表示这是一个pong操作。 •%xB-F:保留的操作代码,用于后续定义的控制帧 |
MASK | 1bit | 表示是否要对数据载荷进行掩码操作。从客户端向服务端发送数据时,需要对数据进行掩码操作;从服务端向客户端发送数据时,不需要对数据进行掩码操作。 |
payload length | 不固定 | 数据载荷的长度,单位是字节。为7位,或者7+16位,或者1+64位。 |
masking-key | 0-4bit | 所有从客户端传送到服务端的数据帧,数据载荷都进行了掩码操作,Mask为1,且携带了4字节的Masking-key。如果Mask为0,则没有Masking-key。 |
payload data | 扩展数据+应用数据 | 扩展数据:如果没有协商使用扩展的话,扩展数据数据为0字节。所有的扩展都必须声明扩展数据的长度,或者可以如何计算出扩展数据的长度。此外,扩展如何使用必须在握手阶段就协商好。如果扩展数据存在,那么载荷数据长度必须将扩展数据的长度包含在内。 应用数据:任意的应用数据,在扩展数据之后(如果存在扩展数据),占据了数据帧剩余的位置。载荷数据长度 减去 扩展数据长度,就得到应用数据的长度。 |
《WebScocket简析》链接:https://xdym11235.com/archives/64.html
具体版权规定详见侧栏版权说明页面