websocket带头部信息请求header_WebSocket协议初探
公司项⽬使⽤WebSocket作为主要的请求⽅式,知其然也要知其所以然,会⽤也需要知道它的基本原理,所以写此⽂章分享下⾃⼰的浅
见,⽂章主要包括以下内容:
WebSocket是什么
WebSocket和Socket区别
建⽴连接
数据帧格式
发送数据
聊天Demo代码: github/madaoCN/Web… 包含tornado写的 Server 和 Client 脚本 和 简单ws使⽤实例的iOS代码WebSocket是什么
WebSocket是⼀种在单个 TCP 连接上进⾏ 全双⼯ 通信的协议,WebSocket使得客户端和服务器之间的数websocket和socket
据交换变得更加简单,允许服
务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成⼀次握⼿,两者之间就直接可以创建持久性的连接,并进
⾏双向数据传输。WebSocket协议在2011年由 IETF 标准化为 RFC 6455
1. 优势
全双⼯,服务器可以主动推送数据给客户端,持久连接,实时性强
省流量,协议控制的数据包头部较⼩,只需要进⾏⼀次完整的http握⼿,后续升级为WebSocket进⾏通信,⽽HTTP的header⼀般有⼏⼗字节,⽽且每次通信都需要携带完整的头部
不仅可以发送⽂本,也可以发送⼆进制,对⼆进制数据⽐较友好
WebSocket和Socket联系
Socket其实并不是⼀个协议,⽽是为了⽅便使⽤TCP或UDP⽽抽象出来的⼀层,是位于应⽤层和传输控制层之间的⼀组接⼝, ⽽
WebSocket和Http⼀样是属于应⽤层协议。
当两台主机通信时,必须通过Socket连接,Socket则利⽤TCP/IP协议建⽴TCP连接。
建⽴连接
Websocket 握⼿过程复⽤了HTTP协议的信道,然后对服务进⾏升级,后续就使⽤Websocket协议进⾏通信,所以只需要⼀次 HTTP 握⼿,服务端就能⼀直与客户端保持通信,直到关闭连接。
⼀、升级请求
GET / HTTP/1.1Host: 192.168.1.250:6767Sec-WebSocket-Version: 13Upgrade: websocketSec-WebSocket-Key: cNtBvwgrxXtqDppb/0mcMw==Connection
与HTTP报⽂不太⼀样的主要是 Connection: Upgrade : 标识要升级协议 Upgrade: websocket : 升级到 Websocket 协议 Sec-WebSocket-Version: 13 : 标明WebSocket协议的版本号 Sec-WebSocket-Key: cNtBvwgrxXtqDppb/0mcMw== 随机⽣成的 ,与服务端响应 Sec-WebSocket-Accept 字段对应,提供基本的防护,防⽌恶意或者⽆意的连接,
⼆、服务端响应报⽂
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketSec-Websocket-Accept: hutW70GFRNI1vI45roqiU0Lu33A=Server: TornadoServer/5.0.2Connection Sec-Websocket-Accept : 是根据客户端 Sec-WebSocket-Key 计算⽽来的
计算⽅法为:
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
简单的python代码验证
#coding=utf8import hashlibimport base64if __name__ == "__main__":    sec_key = "cNtBvwgrxXtqDppb/0mcMw=="    static_key = "258EAFA5-E914-47DA
三、抓包验证
使⽤WireShark对WebSocket连接过程抓包
很直观的可以看到 HTTP三次握⼿ -> 升级协议 -> 使⽤WebSocket通信 的过程
Websocket升级协议报⽂也与上⽂⼀致,⼤家可以⾃⾏运⾏Demo代码,然后使⽤WireShark进⾏抓包验证请求过程和报⽂
数据帧格式
如果我们数据帧格式都不清楚的话,更遑论说了解WebSocket协议了
数据帧概览
数据帧(frame)是WebSocket通信的基本单位,⼀个消息由⼀个或者多个帧组成,内容包括标志位,操作码,掩码,数据长度等
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 8 9 0 1 +-+-+-+-+-------+-+-------------+--------------------------
引⽤⾃ RFC 6455 - Base Framing Protocol 这个⼀章节
数据帧格式
FIN1bit 表明是消息的最后⼀个数据帧,数据帧有可能是第⼀个,同时也是最后⼀个
RSV1, RSV2, RSV3每个1 bit ⼀般都设置为0,如果客户端和服务端采⽤了拓展,那么就可以为⾮0值,⾮0值的含义由拓展来决
定,如果收到了⾮0的值,⽽且未采⽤拓展协商,那么接收终端就应该断开WebSocket连接
操作码4个bit 决定了后续的载荷数据(Payload data)的解析⽅式,如果收到了未知的操作码,那么接收终端就应该断开WebSocket连接,具体的操作码如下:
*  %x0  :  表明了这个⼀个持续帧(continuation frame),当操作码为0时,说明使⽤了数据分⽚,该帧为数据分⽚中的⼀帧*  %x1  :表明了这是⼀个⽂本帧(text frame) Mask 4个bit
表明是否要对载荷数据(Payload data)进⾏掩码操作,如果被置为1,那么 Masking-key 会定义⼀个 32位,4个字节的值,⽤于对载荷数
据(Payload data)的反掩码操作,具体掩码的算法在后续内容中进⾏说明
值得注意的是,只有在客户端向服务端发送数据时,Mask才为1,⽽服务端向客户端发送数据时不需要进⾏掩码操作Masking-key 0 或者4个bit
客户端向服务端发送的数据都进⾏了掩码操作,客户端必须为发送的每⼀个frame选择新的掩码 (随机⽣成),要求是这个掩码⽆法被提供数
据的终端应⽤(即客户端)预测 备注:掩码长度不计⼊载荷数据(Payload data)的长度
Payload length 7 bits 或 7+16 bits 或 7+64 bits 长度为0 - 125 : 那么它就是载荷(playload)的长度 长度为126 : 那么接下来的2个字节(16位⽆符号整型)就是载荷(playload)的长度 长度为127 : 那么接下来的8个字节(64位⽆符号整型)就是载荷(playload)的长度
另外,Payload length采⽤了⽹络字节序,也就是⼤端(big endian数据的⾼字节保存在内存的低地址中),⼤⼩端具体详情请看百度百科
⼤⼩端模式
Payload data(x+y) 字节 载荷数据包括了应⽤数据(x)和拓展数据(y) 应⽤数据 y 字节: 如果存在拓展数据的话,占据了拓展数据之后的帧位置 拓展数据 x字节: 除⾮客户端和服务端进⾏了协商,那么拓展数据应为0,否则拓展数据应当在握⼿过程中明确定义其长度,或者协商如何进⾏长度计算(如果存在拓展数据,那么它的长度应当也计⼊载荷长度中)
掩码的算法
/**original-octet-i为原始数据的第i字节masking-key-octet-j为masking-key的第j个字节transformed-octet-i为掩码计算后的第i个字节*/Octet i of the transformed data ("摘抄⾃ RFC : Client-to-Server Masking
也就是将原始数据和masking-key做异或操作(异或的位数 j = i mode 4),获得的就是转换后的结果
发送数据
WebSocket根据 opcode 操作码来区分操作类型, %x0 %x1 %x2 代表了数据交互帧
%x0 : 表明了这个⼀个持续帧(continuation frame),当操作码为0时,说明使⽤了数据分⽚,该帧为数据分⽚中的⼀帧
%x1 :表明了这是⼀个⽂本帧(text frame)
%x2 :表明了这是⼀个⼆进制帧(binary frame
特别的操作码 %x0 代表使⽤了数据分⽚,消息可能被切分成多个数据帧,笔者发现 tornado 和 SocketRocket 并没有实现数据分⽚,这
⾥就暂不深⼊讨论,详情请参考 RFC: Fragmentation
存活⼼跳ping 和 pong
⼀旦建⽴与服务器的连接,客户端和服务端都可以发起⼀个ping请求,当接收到⼀个ping请求,那么接
收端必须要尽快回复pong请求,通
过这种⽅式,来确认对⽅是否存活,确保客户端、服务端之间的TCP通道保持连接没有断开
ping, pong操作码分别为 %x9 %xA
断开连接
客户端和服务端都可以通过发送带有特殊控制序列 %x8 的数据帧来发起断开连接,⼀旦某⼀端收到该帧,需要也响应⼀个断开帧,之后主
动断开的那端便可以关闭连接了,之前提到过Websocket 握⼿过程复⽤了HTTP协议的信道,那么很⾃然的,断开连接期间也经历了四次
挥⼿的过程
Sec-WebSocket-Key/Accept的作⽤
Sec-WebSocket-Key/Sec-WebSocket-Accept 的算法都是公开的,⽽且也不复杂,仅仅是提供⼀些基础防护,防⽌⼀些意外链接,和
恶意链接
[ WebSocket协议:5分钟从⼊门到精通 ]( wwwblogs/chyingp/p/w… )中已经写得很详细,这边就不做详细探究
数据掩码的作⽤
随着websocket协议被开发出来,⼀项针对代理服务器的攻击(污染那些⼴泛部署的缓存代理服务器)实验也开始进⾏。 ⼀般形式的攻击是跟
被攻击者控制的服务器建⽴连接,并构造⼀个类似WebSocket握⼿⼀样的UPGRADE请求,随后通过UPGRADE建⽴的连接发送看起来就
像GET请求的frame去获取⼀个已知资源(在攻击场景中可能是⼀个点击跟踪脚本或⼴告服务⽹络中的资源) 之后远程服务器会返回某些东
西,就像对于这个伪造GET请求的响应,并且这个响应会被很多⼴泛部署的⽹络中间设备缓存,从⽽达到了污染缓存服务器的⽬的。对于这
个攻击的产⽣的效应,可能⼀个⽤户被诱导访问受攻击者操控的服务器,攻击者就有可能污染这个⽤户以及其他共享相同缓存服务⽤户的缓
存服务器,并跨域执⾏恶意脚本,破坏web安全模型
总结⼀下,掩码的作⽤很重要两点就是 防⽌攻击者获知⽹络链路中传输的原始数据 和 避免缓存

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。