Python3+WebSockets实现WebSocket通信
一、說明
1.1 背景說明
前端時間同事說云平臺通信使用了一個websocket的東西,今天抽空來看一下具體是怎么個通信過程。
從形式上看,websocket是一個應用層協議,socket是數據鏈路層、網絡層、傳輸層的抽象;從應用場合上看,websocket可以使用javascript實現,而socket不能用javascript實現;從實際效果上看,和一般的socket連接用起來沒什么區別。
我們知道http是短連接的,反復建立和銷毀連接比較耗費資源,另外http協議經常頭部內容比主體內容還長也比較浪費資源;websocket可以認為是一個內容使用載荷固定格式的socket長連接。
websocket基本協議格式如下,更多說明見RFC 6455:
1.2 環境說明
當前環境我使用Python3+WebSockets庫,WebSockets直接使用pip安裝即可:
pip install websockets
二、代碼實現
長連接是有狀態的,所以一般在且只在最開始進行一次身份認證,而后通信過程是不需要認證信息。我們這里實現一個簡單的用戶名密碼認證過程。長連接更多內容可參考"長連接與短連接的安全差異討論?”。
另外,注意把代碼中的ip改成自己的。
2.1 python服務端代碼
import asyncio import websockets# 檢測客戶端權限,用戶名密碼通過才能推出循環 async def check_permit(websocket):while True:recv_str = await websocket.recv()cred_dict = recv_str.split(":")if cred_dict[0] == "admin" and cred_dict[1] == "123456":response_str = "congratulation, you have connect with server\r\nnow, you can do something else"await websocket.send(response_str)return Trueelse:response_str = "sorry, the username or password is wrong, please submit again"await websocket.send(response_str)# 接收客戶端消息并處理,這里只是簡單把客戶端發來的返回回去 async def recv_msg(websocket):while True:recv_text = await websocket.recv()response_text = f"your submit context:{recv_text}"await websocket.send(response_text)# 服務器端主邏輯 async def main_logic(websocket, path):await check_permit(websocket)await recv_msg(websocket)start_server = websockets.serve(main_logic, '10.10.6.91', 5678) asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_forever()2.2 python版客戶端代碼
import asyncio import websockets# 向服務器端認證,用戶名密碼通過才能退出循環 async def auth_system(websocket):while True:cred_text = input("please enter your username and password:")await websocket.send(cred_text)response_str = await websocket.recv()if "congratulation' in response_str:return True# 向服務器端發送認證后的消息 async def send_msg(websocket):while True:_text = input("please enter your context:")if _text == "exit":print(f'you have enter "exit", goodbye')await websocket.close(reason="user exit")return Falseawait websocket.send(_text)recv_text = await websocket.recv()print(f"{recv_text}")# 客戶端主邏輯 async def main_logic():async with websockets.connect('ws://10.10.6.91:5678') as websocket:await auth_system(websocket)await send_msg(websocket)asyncio.get_event_loop().run_until_complete(main_logic())2.3 html版客戶端代碼
html版客戶端代碼,只能通過回調函數接收服務端返回的數據,不能主動接收,感覺怪怪的。
<!DOCTYPE HTML> <html><head><meta charset="utf-8"><title>websocket通信客戶端</title><script type="text/javascript">function WebSocketTest() {if ("WebSocket" in window) {// 打開一個web socketvar ws = new WebSocket("ws://10.10.6.91:5678");// 連接建立后的回調函數ws.onopen = function() {//Web Socket已連接上,使用send()方法發送數據ws.send("admin:123456");alert("正在發送:admin:123456");};//接收到服務器消息后的回調函數ws.onmessage = function (evt) {var received_msg = evt.data;if (received_msg.indexOf("sorry") == -1) {alert("收到消息:"+received_msg);}};// 連接關閉后的回調函數ws.onclose = function() {//關閉websocketalert("連接已關閉...");};} else {//瀏覽器不支持WebSocketalert("您的瀏覽器不支持 WebSocket!");}}</script></head><body onload="WebSocketTest()"></body> </html>三、通信數據包截獲及通信過程分析
以下數據包基于上邊的python服務端和html版客戶端,再次強調注意把代碼中的ip改成自己電腦當前的ip。
3.1 wireshark通信數據包截獲及通信過程分析
wireshark攔截數據包后可使用過濾器表達式"websocket"進行過濾:
我們追蹤數據流可以更清晰地看清websocket的通信過程,可以看到先是用http完成了建立連接,然后切換到websocket協議。
再看具體數據流也確實如此,先用兩個http包建立連接,而后是websocket通信.
3.2 burpsuite通信數據包截獲及通信過程分析
和正常配置代理即可,burpsuite能識別和攔截websocket數據包,如下圖:
不過和一般http請求有區別的是,websocket請求會被單獨匯總到“WebSocket history”選項卡,而不是和http請求混在"HTTP history"選項卡。
3.3 開發者工具通信數據包截獲及通信過程分析
FIreFox開發者工具只能看到簡歷websocket連接的兩個http數據包,沒看到怎么查看具體傳輸內容,Chrome開發者工具Frames選項卡可以,如下:
參考:
https://websockets.readthedocs.io/en/stable/intro.html
https://www.runoob.com/html/html5-websocket.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Python3+WebSockets实现WebSocket通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: web压测工具http_load原理分析
- 下一篇: web安全攻防从入门到放弃-记录