websocket 安全需三段式校验:握手时严格校验 origin 和一次性动态 token,连接中对每条消息按 socket id 限频并绑定上下文,断连后立即清理 redis 中相关缓存。

WebSocket 连接阶段必须校验 Origin,不能只靠 User-Agent
直接在 WebSocket 处理逻辑里检查 User-Agent 几乎无效——爬虫可随意伪造,且现代无头浏览器(如 Playwright)默认 UA 和真实 Chrome 几乎一致。真正有效的第一道防线是 Origin 头校验:服务端在升级握手(Upgrade 请求)时,必须比对请求头中的 Origin 是否在白名单内(如 https://your-app.com)。Nginx 或应用层都可拦截,但必须在连接建立前完成。
常见错误现象:
– 用 req.headers['user-agent'] 做判断,结果大量恶意连接成功建立
– 白名单写成 http://* 或留空,等同于放行所有来源
– 没有 fallback:当 Origin 缺失(如某些本地测试环境)时未设安全兜底,导致生产误放行
实操建议:
– Node.js(ws 库)中,在 verifyClient 钩子里解析并校验 origin 字段
– 若使用 Nginx 反代,加 if ($http_origin !~ ^https?://(your-app\.com|localhost)) { return 403; }
– 禁止将校验逻辑后移到 connection 事件之后——此时连接已建立,资源已被占用
WebSocket 消息层需绑定动态 token,不能依赖 session 或 cookie
HTTP 的 Cookie 或 session_id 在 WebSocket 升级后就不再自动传递,且无法被中间件统一拦截。如果仅靠登录态放行,攻击者可先用合法账号获取 token,再复用到批量连接中。必须为每个 WebSocket 连接单独签发一次性的、带上下文的 action_token。
使用场景:
– 用户点击“实时行情”按钮时,前端先调用 /api/get-ws-token 获取短期 token
– 该 token 存入 Redis,键为 ws_token:{uuid},值含 ip、user_id、expires_at、used: false
– 建立 WebSocket 时,将 token 放在查询参数(如 wss://api.com/ws?token=a1b2c3)或自定义 header(需客户端支持)
为什么这样做:
– 防重放:token 用过即失效,且超时自动清理
– 绑定 IP:拒绝来自不同 IP 的重复使用
– 解耦会话:不依赖 HTTP session 生命周期,避免长连接期间 session 过期导致异常断连
消息频率与连接数必须双重限流,单靠 Nginx 不够
Nginx 的 limit_conn 只能控并发连接数(如 limit_conn perip 5),但无法限制单个连接内的消息频次。恶意脚本可建一个连接,然后每秒发 1000 条 ping/pong 或业务消息,照样打垮后端。
容易踩的坑:
– 仅在 HTTP 层限流(如 limit_req_zone $binary_remote_addr zone=ws_handshake:10m rate=10r/m),忽略 WS 消息层
– 使用全局计数器(如 Redis key ws_msg_count)而不带连接 ID,导致多用户共享配额
– 未设置消息处理超时,一条恶意大 payload 占住 worker 进程
实操建议:
– 服务端为每个 ws.socket.id 创建独立计数器,例如 Redis key ws_rate:{socket_id}
– 每收到一条业务消息,执行 INCR + EXPIRE(窗口 60 秒),超阈值立即 socket.close()
– 对非心跳类消息(如 subscribe、send_order)单独限流,比普通消息更严(如 5 次/分钟)
加密传输必须用 wss,且禁用不安全 TLS 版本
明文 ws 协议下,所有消息(包括 token、业务数据)均可被中间人截获和篡改。即使前端做了参数加密,密钥也可能从 JS 中被提取。强制 wss 是底线。
性能与兼容性影响:
– TLS 1.2+ 是硬性要求,TLS 1.0/1.1 已被主流浏览器弃用,且存在已知漏洞(如 POODLE)
– 不要为了兼容旧设备开启 ssl_protocols TLSv1 TLSv1.1,这等于主动降级安全水位
– 证书必须由可信 CA 签发,自签名证书会导致前端 WebSocket 实例直接报 ERR_CONNECTION_REFUSED
关键检查点:
– Nginx 配置中确认 listen 443 ssl http2 且 ssl_certificate 路径正确
– 后端 WebSocket 服务(如 ws、uWebSockets)不自行处理 TLS,交由反代终结
– 浏览器控制台验证协议是否为 wss://,而非降级为 ws://
最常被忽略的一点:WebSocket 的防爬不是「一次性配置」,而是贯穿连接生命周期的三段式校验——握手时验 Origin + token,连接中验消息频次与上下文,断连后清空所有关联缓存(Redis 中的 token、rate 计数器、IP 统计)。少一环,就可能被绕过。











