WebSocket本身不防爬,所有防护均需在握手前、握手时或消息层实现;Origin校验未白名单化、Cookie依赖未同步、Referer/User-Agent校验容错不足是握手阶段最易被绕过的三点。

WebSocket 本身不防爬,所有“防爬”动作都发生在握手前、握手时、或连接建立后的消息层——指望协议自带防护等于没设防。
WebSocket 握手阶段最容易被绕过的三个验证点
很多网站只在 Sec-WebSocket-Key 校验上做文章,却忽略真实攻击面。实际抓包会发现,真正卡住爬虫的往往是以下三处:
- Origin 头校验未白名单化:服务端只检查
Origin是否存在,没比对具体域名,导致用curl -H "Origin: https://any-site.com"就能过 - Cookie 依赖未同步:前端 JS 在建立 WebSocket 前先请求一个 /auth 接口种下加密 Cookie,但 Python 爬虫没走这步,直接连
wss://...就被 403 - Referer 或 User-Agent 硬编码校验:比如只允许
User-Agent: Mozilla/5.0 (Macintosh),但没做大小写/空格容错,user-agent小写头就直接放行
Python 连接带 Token 认证的 WebSocket 必须传对的三个 header
Flask + websockets 或 FastAPI + starlette.websockets 后端若要求认证,客户端必须在握手请求中带齐:
-
Authorization: Bearer eyJhbGciOi...—— JWT 必须完整,不能截断或漏等号 -
Origin: https://trusted-domain.com—— 必须和服务端白名单完全一致(含协议、端口、末尾斜杠) -
Cookie: sessionid=abc123; csrftoken=xyz789—— 若后端用 Django/Flask-Login,session cookie 缺一不可;注意httpx默认不自动携带,得手动塞进extra_headers
示例(websockets 库):
import websockets
uri = "wss://api.example.com/ws"
headers = {
"Origin": "https://example.com",
"Authorization": "Bearer xxx",
"Cookie": "sessionid=abc123;"
}
async with websockets.connect(uri, extra_headers=headers) as ws:
await ws.send('{"type":"auth"}')
数据帧层加密不是可选项,而是反爬生效的关键环节
即使你把握手做得天衣无缝,只要服务端推送的数据是明文 JSON,爬虫拿到连接后就能直接解析。而多数实时数据平台(如体育比分、行情)正是在这里埋雷:
- 二进制帧 + 自定义 XOR 密钥:比如每帧前 2 字节是长度,后 N 字节是 payload,用固定字节(如
0x5a)逐字节异或解密 - Base64 + 时间戳动态偏移:payload 先 base64,再把每个字符 ASCII 码减去当前分钟数(
int(time.time() // 60)),客户端需实时同步时间 - 混淆字段名:
{"a":"2026-05-28T17:45:00Z","b":123,"c":"live"},对应真实字段为timestamp、score、status,映射表藏在前端 JS 里
这类加密不会出现在 RFC 文档里,只能靠逆向前端 JS 或抓包对比不同时间点的帧内容来还原。
WSS 加密传输 ≠ 数据安全,别被 TLS 蒙蔽
启用 wss:// 只保证链路加密,不解决身份冒用和数据逻辑层泄露。常见误判:
- 以为用了 WSS 就不用 JWT:错。TLS 防的是中间人,防不了合法域名下的恶意页面(CSWSH 攻击)
- 证书自签就敢上线:浏览器会报错,且部分 Python 客户端(如旧版
websocket-client)默认不校验证书,反而让调试变简单,生产环境必须用可信 CA 证书 - 忽略心跳包里的行为指纹:有些服务在 ping/pong 帧里嵌入设备 ID 或 canvas 指纹 hash,单纯复现握手无法维持长连接
真正难啃的骨头,永远不在协议规范里,而在服务端那几行没文档的校验逻辑和前端 JS 里一闪而过的密钥生成函数。











