《吐血整理》高級系列教程-吃透Fiddler抓包教程(33)-Fiddler如何抓取WebSocket數據包
1.簡介
本來打算再寫一篇這個系列的文章也要和小夥伴或者童鞋們說再見了,可是有人留言問WebSocket包和小程式的包不會抓,那就關於這兩個知識點宏哥就再水兩篇文章。
2.什麼是Socket?
在電腦通訊領域,socket 被翻譯為「套接字」(套接字=主機+埠號),它是電腦之間進行通訊的一種約定或一種方式。通過 socket這種約定,一台電腦可以接收其他電腦的數據,也可以向其他電腦發送數據
socket起源於Unix,而Unix/Linux基本哲學之一就是「一切皆文件」,都可以用「打開open –> 讀寫write/read關閉close」模式來操作。
我的理解就是Socket就是該模式的一個實現,它只是提供了一個針對TCP或者UDP編程的介面:即socket是一種特殊的文件,一些socket函數就是對其進行的操作(讀/寫IO、打開、關閉)。
socket抽象層在網路中的位置圖解,如下圖所示:
3.Socket通訊流程
Socket通訊流程,如下圖所示:
根據socket通訊基本流程圖,總結通訊的基本步驟:
伺服器端:
第一步:創建一個用於監聽連接的Socket對像;
第二步:用指定的埠號和伺服器的ip建立一個EndPoint對像;
第三步:用socket對像的Bind()方法綁定EndPoint;
第四步:用socket對像的Listen()方法開始監聽;
第五步:接收到客戶端的連接,用socket對像的Accept()方法創建一個新的用於和客戶端進行通訊的socket對像;
第六步:通訊結束後一定記得關閉socket;
客戶端:
第一步:建立一個Socket對像;
第二步:用指定的埠號和伺服器的ip建立一個EndPoint對像;
第三步:用socket對像的Connect()方法以上面建立的EndPoint對像做為參數,向伺服器發出連接請求;
第四步:如果連接成功,就用socket對像的Send()方法向伺服器發送資訊;
第五步:用socket對像的Receive()方法接受伺服器發來的資訊 ;
第六步:通訊結束後一定記得關閉socket;
4.python實現一個客戶端與服務端的通訊
4.1函數
Socket對象方法:
服務端:
函數 | 描述 |
---|---|
.bind() | 綁定地址關鍵字,AF_INET下以元組的形式表示地址。常用bind((host,port)) |
.listen() | 監聽TCP,可以掛起的最大連接數,該值至少為1,一般設為5即可 |
.accept() | 被動接受TCP客戶端的連接 |
客戶端: |
函數 | 描述 |
---|---|
.connect() | 初始化伺服器連接 |
.connect_ex() | 是對connect()函數的擴展,當出錯時返回出錯碼,不報異常 |
其它函數: |
函數 | 描述 |
---|---|
.recv() | 接收數據,數據以字元串的形式返回,bufsize指定接收的最大數據量。 |
.send() | 發送數據,將string中的數據發送到連接的套接字,返回值是要發送的位元組數量,通常使用.encode()函數對數據進行轉碼 |
.senddall() | 發送完整的數據,在返回之前會嘗試發送所有數據,成功返回None,失敗則拋出異常。 |
.recvfrom() | 與recv()函數類似,不同的是返回值是(data,address),其中data是包含接收數據的字元串,address是發送數據的套接字地址。 |
.sendto() | 發送UDP數據,將數據發送到套接字,形式是(ipaddr,port)的元組。 |
.close() | 關閉套接字 |
4.2服務端
使用socket函數來創建一個socket對象,並設置一個socket服務,然後通過bind(hostname,port)函數來指定一個埠,使用socket對象的accept方法,等待客戶端的連接,並返回connection對象。
具體步驟為:
#創建服務端套接字 serversocket=socket() #把地址綁定到套接字 serversocket.bind() #對連接進行監聽 serversocket.listen() #使用一個while進行循環,並接收客戶端的連接 while True: serverclient=serversocket.accept() while True: #接收已發送 serverclient.recv() serverclient.send() #關閉客戶端套接字 serverclient.close() #關閉服務端套接字 serversocket.close()
4.3具體程式碼實現
實現功能:通過while實現循環接收客戶端發送的數據,並對客戶端發送的數據進行顯示並返回給客戶端數據,返回給客戶端的數據資訊後加入時間戳。新建一個文件server.py。
import socket import sys import time serversocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) host=socket.gethostname()#獲取本地主機名 port=9999 #綁定埠號 serversocket.bind((host,port)) #設置最大連接數 serversocket.listen(5) while True: print('伺服器啟動,監聽客戶端鏈接') clientsocket,addr=serversocket.accept() print('鏈接地址:%s' % str(addr)) while True: try: data=clientsocket.recv(1024) except Exception: print('斷開的客戶端:',addr) break print('客戶端發送內容:',data.decode('utf-8')) reply=input('回復:').strip() if not reply: break msg=time.strftime('%Y-%m-%d %X')#獲取結構化時間戳 msg1='[%s]:%s'% (msg,reply) clientsocket.send(msg1.encode('utf-8')) clientsocket.close() serversocket.close()
4.4客戶端
創建一個客戶端用來連接以上服務的的服務,使用socket.connect()方法打開一個TCP連接到主機,連接後可以從服務端獲取數據,在操作完成後關閉連接。
具體步驟為:
#創建客戶端的套接字 client=socket() #嘗試連接伺服器 client.connect() #發送並接收數據 client.send() client.recv() #關閉客戶端套接字 client.close()
4.5具體程式碼實現
新建一個文件client.py。
import socket import sys s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) host=socket.gethostname() port=9999 s.connect((host,port)) while True: data= input('>>').strip() if not data: break s.send(data.encode('utf-8')) msg=s.recv(1024) if not msg: break print(msg.decode('utf-8')) s.close()
4.6測試
使用cmd命令行中打開到程式碼所在文件目錄,執行python 服務端文件名.py,再另打開一個cmd命令介面執行 python 客戶端文件名.py。
1.在cmd中運行服務端程式碼,運行結果,如下圖所示:
2.在cmd中運行客戶端程式碼,運行結果,如下圖所示:
好了到此就實現了,但是宏哥抓不到包,不知道是不是因為服務端和客戶端都在宏哥本地一台電腦的原因,算了宏哥直接網上找了一個在線的演示給大家。
5.實戰抓WebSocket包
由於時間關係,宏哥沒有嘗試將客戶端和伺服器分開看看是否可以抓到包,然後在網上找了一個地址://coolaf.com/tool/chattest 演示給大家。具體操作步驟如下:
1.Fiddler V4.5以上版本,rules>customize rules,加入如下程式碼,把websocket通訊日誌加入log,如下圖所示:
2.class Handler 類中添加,添加的程式碼如下:
static function OnWebSocketMessage(oMsg: WebSocketMessage) { // Log Message to the LOG tab FiddlerApplication.Log.LogString(oMsg.ToString()); }
3.打開PC版的聊天室(宏哥提供的演示地址),並刷新Fiddler,會看到一個WS圖標的請求,雙擊該請求,右邊會出現websocket的tab頁,如下圖所示:
PC版在線聊天,如下圖所示:
Fiddler抓的WebSocket包,如下圖所示:
4.切換到log tab頁可以看到通訊的數據往來,如下圖所示:
5.通過F12也可以看到websocket的請求資訊,進入聊天室後,F12>network>濾斗(放大鏡左邊的這個紅色圖標)>WS,雙擊name裡邊這個,即展開相關的詳情,在詳情里選中某條數據,底部會進一步顯示全部資訊,如下圖所示:
6.小結
將那段程式碼保存後就可以在Fiddler右邊欄的Log標籤里,看到WebSocket的數據包。到了這裡,還有一個情況要說明,就算是有工具可以抓到WebSocket中的包,看到的也不一定是明文。這個要看傳輸的水是什麼,如果是普通水那誰都可以分析;但如果是水銀,那這個分析水的設備很可能就顯示亂碼了。 所以也就有同學明明使用了可以抓WebSocket包的程式,卻抓出來的是亂碼。那是因為別人傳輸的是二進位數據流(比如AMF包),而不是JSON之類的對人類可讀的明文。而宏哥演示的網址是用於測試的因此沒有考慮安全進行加密,所以使用的是明文,大家可以看到客戶端和服務端相互發送的資訊內容,關於如何加密宏哥在這裡就不做贅述了因為它不是今天的重點內容。
6.1關於websocket
1.HTML5提供的在單個TCP上運行的全雙工通訊協議(應用層協議)
2.客戶端和伺服器之間只需要進行一次握手就能夠實現雙向通訊,進行數據傳輸
3.相比較Ajax輪詢機制需要不斷地從客戶端間隔性發送請求,傳輸不必要的頭部數據,消耗大量的頻寬,websocket節省了服務資源和寬頻
4.通過send()方法發送數據給客戶端,客戶端通過onmessage接收伺服器返回的數據