Websocket协议浅析

本文总阅读量
  1 min to read  

前几天在爬虫单中看见一个wss://xxxxxx.com的爬取,借机学习了Websocket协议

P.s 这个博彩网站是我见过的最难的单,wss数据被协议帧层面加密,定时发送options请求刷新cookie


WebsocketHtml5提供的一种基于TCP的全双工式通讯协议,它复用了Http连接的握手通道,它使得B/S之间完全平等。

由于Http协议是一种无状态,无连接(keep-alive除外),不持久的通讯协议,且服务器的Response是绝对被动的,浏览器不请求,它就没法响应。

但在现实场景中很多时候都需要进行推送,例如我们的手机上,各个App都会定时推送消息给客户端,原理是App后台驻留,由事先建立的TCP长连接定时请求服务器,也就是轮询,这就引出了pollinglong polling


polling

就是轮询,定时向服务器询问是否有新信息,这样的方式对于资源的消耗可想而知

long polling

阻塞查询,当请求服务器后,没有接到新消息就会阻塞,直到服务器返回消息,这对于服务器的并发有很大考验


Websocket

Websocket协议则是用了回调的形式,与传统的异步相同

它允许服务器主动向浏览器发送消息,这样就解决了上诉两种方案的弊端

它与Http相同,也是先建立Tcp连接,再发送协议标准的数据帧。且它复用Http的握手通道,即客户端借用Http协议与服务器升级Websocket协议,后续进行WS通讯

ws也有ssl层加密,加密后为wss,类似http/https

这里我们发起一个ws请求,网址为:Websocket在线测试

请求头:

Accept: text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
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
Cache-Control: no-cache
Connection: keep-alive, Upgrade
DNT: 1
Host: 121.40.165.18:8800
Origin: http://www.blue-zero.com
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: W/kolcgVmU5mUVJi3i4tpA==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/59.0

响应头:

Connection: Upgrade
Sec-WebSocket-Accept: yjko/QGDLpz4adhGrf0jHwrlnG0=
Upgrade: websocket

可以看到请求头中有upgrage/connection的变化,为升级httpws,加上sec-*的三个字段,key为浏览器随机生成的base64编码字符串


当使用Firefox F12或BurpSuite抓包时,URL会显示http://,但在使用脚本请求时需更正协议名为ws://

抓包过程中火狐的数据响应会显示在JS控制台,Burp会有Websocket History标签显示,但它俩几乎都看不到最初的握手数据。所以在分析ws这点上,还是用Chrome比较省心,可以直接在Frame查看所有的数据帧


接下来爬取一个网站快讯通,里面的新闻数据全是由ws传输的

写脚本请求,函数库websocket

import requests
import websocket

def get_token():
    token_url = "http://viewapi.yn.com/index/kxauth"
    r = requests.get(token_url)
    token = r.json()["data"]["token"]
    return token

def ws_post():
    headers = {
        'Origin': 'http://viewapi.yn.com',
        'Pragma': 'no-cache',
        'Sec-WebSocket-Extensions': 'permessage-deflate',
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0'
    }
    url = f"ws://118.31.236.175:9502/?token={get_token()}"
    ws = websocket.create_connection(url, header=headers)
    ws.send('{"cmd":"login", "number":100, "codes":["CJRL","KUAIXUN"]}')
    print(ws.recv())
    ws.close()

def main():
    ws_post()
    
main()

正常获取到数据