导语:上篇拆了握手那一刻的八大致命风险,这篇聊握手之后。WebSocket 一旦升级成功,后续每条消息帧都是红队的游乐园——聊天/通知里的 IDOR 越权读写,能让 A 看见 B 的私信;连接洪泛 DoS 能把网关内存打满。本文基于 harsh-bothra/learn365 day14 实战清单展开。
一、IDOR 越权:换个 sid 就把别人私信翻出来
WebSocket 通道一旦建立,服务端靠”业务参数”识别”你是谁、要看哪条消息”。这些参数往往写在帧 payload 的 JSON 里,和 HTTP 参数一样可改——这就是 WebSocket 版的 IDOR(Insecure Direct Object Reference,不安全直接对象引用)。
1.1 测试步骤
harsh-bothra 给的红队清单非常直接,落到 Burp 里就是这套动作:
- 浏览器里打开应用,登录攻击者账号 A,找到 WebSocket 通信端点。
- 在 Burp Suite 拦截 WebSocket 消息(Burp 1.6+ 已原生支持 WS 拦截和修改)。
- 在消息帧里翻 payload,找形如
"sid": "用户A的ID"、"uuid": "..."、"role": "user"、"orderId": "10086"之类的字段——任何能唯一定位一个实体/对象的参数都是目标。 - 把这个字段值改成目标受害者 B 的 ID,重放帧。
- 看 A 的客户端有没有收到”按理只该 B 收到”的消息——收到就是 IDOR。
1.2 真实攻击链:聊天室的 sid 越权
原文给的典型场景:聊天应用里,攻击者给受害者发一条消息。帧里带 "sid": ""。改成受害者的 sid 重放——A 的客户端收到”来自 B 的消息”,但 B 啥也没干。这就是经典的 IDOR。
更狠的还有:
- 读取类越权:帧里带
"orderId": "1001",改成1002、1003顺序遍历,把别人的订单详情全部拉下来。 - 写类越权:金融场景里把
"accountId": "self"改成"accountId": "victim",转账消息照常发出。 - 角色提升:帧里
"role": "user"改成"role": "admin",后台可能就直接放行管理操作。 - 跨租户越权:SaaS 多租户系统里
"tenantId": "tnt_A"改成"tnt_B",直接读别人租户的数据。
1.3 和 HTTP IDOR 一样套路
所有 HTTP 工作流里 IDOR 的检查项,全部用一遍就行:
- 水平越权:同权限用户之间 ID 互换。
- 垂直越权:低权限 ID 改高权限 ID。
- 遍历枚举:自增 ID 顺序遍历。
- UUID 类:UUID v1 可推断时间戳,v4 也可能被泄露泄露的会话表反查。
- 加密 token 类:JWT/session ID 改成别人的。
工具配合:
| 工具 | 用途 |
|---|---|
| Burp Suite | WS 拦截 + 修改 + 重放 |
| WebSocket Turbo Intruder | 高速批量重放帧 |
| mitmproxy + WS 插件 | 命令行抓包改包 |
| wsfuzzer / WS-Attacker | 协议级模糊测试 |

二、DoS 拒绝服务:把网关内存打到 OOM
WebSocket 设计上是长连接,服务端要为每个连接分配 fd、内存、状态机资源。攻击者只要能批量起连接,就能把服务端资源吃满。
2.1 连接洪泛
原文里第一条:”WS allows any number of connections to the target server.”
这就是连接洪泛的根因。攻击者开一台机器,挂上万条空闲长连接,服务端就得上万份 socket buffer + 状态表。Web 应用网关常见连接上限在 1k-10k,几秒就能打满。
实测套路:
# 用 Python 一行起 5000 个空闲 WS 连接
python3 -c "
import asyncio, websockets
async def hold():
while True:
try:
async with websockets.connect('wss://target/chat') as ws:
await ws.recv() # 阻塞等消息
except: pass
async def main():
await asyncio.gather(*[hold() for _ in range(5000)])
asyncio.run(main())
"
或用现成工具:
- WebSocket Flooder(GitHub 一堆):并行起几千连接,每个发 ping 保活。
- Slowloris-WS:发半个握手包挂住,让服务端在 SYNC_WAIT 状态堆积。
- 黄金眼:先用慢速建立大量连接占用 fd,再触发服务端业务处理,把 CPU 也吃光。
2.2 应用层 DoS
原文第二条:”Try sending multiple requests to initiate a WS connection in a short time.”
这条更阴险。WebSocket 握手是 HTTP Upgrade,服务端收到请求要走完握手 + 业务校验 + 用户鉴权 + 状态初始化才会进入稳定连接态。如果业务逻辑重(比如握手成功要查 DB、要分配内存、要发欢迎消息),攻击者可以:
- 1 秒内发起 1 万次握手请求,服务端 CPU 全耗在握手处理上。
- 握手成功后立刻发畸形帧,触发服务端解析异常抛出,CPU 浪费在异常处理。
- 发巨型帧(payload 几 GB),服务端要么 OOM,要么协议栈崩。
更阴的是”应用级卡顿”——握手后立刻断开循环重连,让服务端反复执行”建连-分配资源-断连-回收”,中途还插几个慢帧,最后变成 GC 不停、服务端响应延迟 P99 从 50ms 涨到 5s。
2.3 攻击分类图

三、纵深防御:服务端必须做的五件事
3.1 IDOR 侧
- 服务端永远不信任帧里带的 ID,必须从会话 token 解析出”真实用户”,再用这个用户去查对象——而不是用帧里传过来的 ID。
- 所有读写操作走”我的对象/他的对象”鉴权层,水平越权直接 403。
- 业务 ID 用不可预测的 ID(UUID v4、雪花 ID、自增 ID 加密混淆),不让攻击者枚举。
- 关键操作加二次校验(转账 / 删除 / 修改权限必须重新输密码或二次确认)。
- WS 服务器侧日志全留:每条帧的发送者、目标值、操作类型全部审计,事后追溯。
3.2 DoS 侧
- 连接数限速:单 IP / 单用户最大并发连接数(比如 ≤ 100),超过直接 RST。
- 握手速率限制:单 IP 握手 QPS 上限,超出返回 429。
- 帧大小限制:单帧 payload 上限(常见 64KB-1MB),超出直接断连。
- 空闲超时:超过 N 分钟无消息自动关闭,回收 fd 和内存。
- 边缘 WAF 兜底:CDN / WAF 层先把畸形握手挡掉,不要让业务网关直接面对公网洪流。
四、回顾与下篇预告
day13 拆了握手那一刻的八大致命风险,day14 这两条路径是握手成功之后红队最爱打的——IDOR 把权限打穿,DoS 把资源打满。两类问题在传统 HTTP 工作流里也有,但放到 WebSocket 上反而更危险,因为攻击者更容易”潜伏”在长连接里慢挖。
下篇 day15「Prototype Pollution」,把 JavaScript 对象污染放到原型链上玩——这玩意儿一旦和 Web 模板、Node 后端、JS 沙箱混在一起,杀伤力比 WebSocket 这两篇加起来还大。
原文出处:harsh-bothra/learn365 · day14 延伸阅读:OWASP WebSocket Security · PortSwigger WebSocket labs














暂无评论内容