恶意WebSocket连接必须在服务端握手阶段拒绝,否则消耗资源;需校验Origin和Sec-WebSocket-Protocol、IP限流、连接级速率限制、动态黑名单,并确保所有校验在OPEN前完成。

恶意 WebSocket 连接无法靠前端拦截,必须在服务端握手阶段就拒绝——否则每个多余连接都在消耗 socket 句柄、内存和事件循环资源。
WebSocket 握手阶段必须校验 Origin 和子协议
浏览器发起 ws:// 或 wss:// 连接时,HTTP Upgrade 请求中会携带 Origin 和 Sec-WebSocket-Protocol 头。不校验这两个字段,攻击者可从任意网页(如恶意钓鱼页)直连你的服务,构成 CSWSH(跨站 WebSocket 劫持)风险。
- 只接受白名单
Origin,例如https://app.example.com;严禁使用通配符*或空值 - 拒绝缺失
Sec-WebSocket-Protocol的请求,或只允许已知协议名(如["json-v1", "binary-v2"]),curl / 自写脚本常忽略该头,可筛掉一批低级扫描器 - Node.js
ws库示例中,server.on('upgrade')回调里必须做这两步判断,失败直接调用socket.destroy()
按 IP 限流:用 Nginx 做第一层连接数控制
应用层限流总有延迟,Nginx 能在 TLS 握手后、HTTP Upgrade 前就掐断超额连接,更早释放系统资源。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 用
limit_conn_zone按真实客户端 IP 建立连接池:limit_conn_zone $binary_remote_addr zone=wsip:10m; - 在
location /ws块中启用:limit_conn wsip 5;(单 IP 最多 5 个并发 WebSocket) - 注意:需配合
map提取真实 IP(如处理了 X-Forwarded-For),否则所有连接会被识别为反向代理 IP - 此配置对高频建连(秒级新建数十连接)效果显著,但无法防 IP 池轮换攻击
服务端连接级速率限制:每个 socket 独立计数器
共享全局计数器会导致合法用户被误杀;按连接实例维护滑动窗口,才能精准压制恶意客户端。
- 在
connection事件中为每个ws实例绑定独立的RateLimiter(如基于 Redis 的 sliding window) - 典型阈值:每秒 ≤ 5 条业务消息、每分钟 ≤ 10 次
ping、单条消息 ≤ 64KB —— 超出即ws.close(4408, 'Rate limit exceeded') - 避免在
message回调里做同步耗时校验(如 JWT 解析),应预加载或缓存验证结果 - PHP Ratchet 用户可用
IpBlackList装饰器 + 自定义中间件组合实现,但注意其默认不支持动态黑名单热更新
动态黑名单必须支持运行时增删,且作用于握手前
静态配置的黑名单(如 Nginx deny)无法响应实时攻击;真正有效的黑名单要能在检测到异常行为后 1 秒内生效,并阻止下一次握手。
- 黑名单数据必须存在 Redis 或本地 LRU cache 中,避免每次握手都查数据库
- 校验逻辑要嵌入
upgrade阶段(Node.js)或onOpen前(Ratchet),而非连接建立后 - 常见触发条件:1 分钟内 3 次认证失败、连续发送非法 JSON、非预期子协议 + 空
Origin - 不要依赖客户端 IP 单一维度——同一 NAT 后可能有多个正常用户;建议组合 IP + User-Agent 指纹 + TLS JA3 hash 提升精度
真正的防护难点不在代码怎么写,而在于「拒绝时机」:所有校验必须发生在 socket 句柄分配之后、WebSocket 协议状态变为 OPEN 之前。任何延迟到 onMessage 才处理的逻辑,都意味着攻击者已经成功占用了服务端一个完整连接资源。

















