Websocket协议浅析

  1 min to read  

List [CTL]

    前几天在爬虫单中看见一个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()
    
    

    正常获取到数据