WebSocket 逆向和 HTTP 有什么不同
HTTP 协议模拟是"一次性请求"的复制,WebSocket 是长连接状态机的复刻:握手、鉴权、心跳、消息编解码、重连,每个环节都有坑。抓包工具对 WS 的支持也弱于 HTTP(Charles 能看但不直观),先建立正确的分析姿势。
分析姿势:先看懂消息格式
Chrome DevTools 的 Network → WS → Messages 标签页能看到所有帧。重点观察:
- 消息格式:JSON?protobuf?自定义二进制?(JSON 最好办,protobuf 按前文方法还原,自定义二进制最麻烦)
- 消息类型字段:一般有个
type/cmd/op字段区分消息种类(心跳、业务、推送) - 鉴权时机:握手 URL 带 token?还是连接后第一条消息鉴权?
模拟客户端的骨架
import asyncio, websockets, json
class WSClient:
def __init__(self, url, token):
self.url = url
self.token = token
self.seq = 0
async def connect(self):
async with websockets.connect(
self.url,
extra_headers={'User-Agent': '...', 'Origin': 'https://target.com'},
ping_interval=None, # 关掉库的自动心跳,自己控制
) as ws:
await self.auth(ws)
await asyncio.gather(
self.heartbeat_loop(ws),
self.message_loop(ws),
)
async def auth(self, ws):
# 连接后首条消息鉴权(格式从抓包还原)
await ws.send(json.dumps({
'type': 'auth', 'token': self.token, 'seq': self.next_seq()
}))
async def heartbeat_loop(self, ws):
while True:
await asyncio.sleep(30) # 心跳间隔按抓包观察值
await ws.send(json.dumps({'type': 'ping', 'seq': self.next_seq()}))
async def message_loop(self, ws):
async for msg in ws:
data = json.loads(msg)
await self.handle(data)精髓一:心跳的魔鬼细节
心跳是 WS 模拟最容易露馅的地方:
- 间隔要随机化。真实客户端的心跳间隔是"30 秒 ± 网络抖动",你每 30.000 秒准点发,统计学上就是机器人。
sleep(30 + random.uniform(-2, 2)) - 心跳内容有序列号。很多协议的心跳带递增 seq,断连重连后 seq 的处理规则(重置还是继续)要按原协议来
- 服务端心跳超时。服务端一般 2-3 倍心跳间隔没收到就断连。你的心跳线程必须独立且可靠——主循环卡住时心跳不能停
精髓二:重连状态机
真实客户端的重连逻辑是协议的一部分:
async def run(self):
retry = 0
while True:
try:
await self.connect()
retry = 0
except Exception as e:
retry += 1
# 指数退避 + 抖动,和真实客户端行为一致
delay = min(60, (2 ** retry)) + random.uniform(0, 3)
await asyncio.sleep(delay)要点:指数退避(1s、2s、4s…封顶 60s)+ 随机抖动。固定间隔重连(每 5 秒硬刚)在服务端看来是攻击特征。
精髓三:二进制协议的处理
消息是 protobuf/自定义二进制时:
# protobuf:用还原的 proto 文件编解码
msg = AuthMessage()
msg.token = self.token
await ws.send(msg.SerializeToString())
# 收消息
async for raw in ws:
msg = ServerMessage()
msg.ParseFromString(raw)自定义二进制协议(无 proto)时,先用抓包样本做格式逆向:固定字段偏移、长度前缀、类型标识,逐字节对照多条消息找规律。WebSocket 帧本身有头部开销,分析时区分"WS 帧头"和"应用层协议头"。
总结
- WS 模拟是状态机复刻:握手、鉴权、心跳、重连缺一不可
- 心跳间隔随机化,序列号规则对齐原协议
- 重连用指数退避+抖动,别固定间隔硬刚
- 二进制消息先还原格式,protobuf 按字段号重建
交流微信:run1255