必须在握手阶段鉴权,因onopen后连接已升级为websocket协议,服务端无法拒绝未授权连接,且恶意用户可跳过auth消息直接发送业务帧,导致资源占用与安全风险。
websocket 连接必须在握手阶段完成鉴权,不能等 onopen 触发后再发 token —— 否则连接已建立,未授权通道已经存在,攻击者可直接利用。
为什么不能在 onopen 里发 Token?
这是最常被误用的“懒办法”:先连上,再 send 一条 {"type":"auth","token":"..."}。问题在于:
- 连接已升级为 WebSocket 协议,服务端无法拒绝或中断(不像 HTTP 可直接返回 401);
- 中间代理、CDN、WAF 等可能缓存或记录该连接,但不会校验后续消息里的 Token;
- 恶意用户可跳过 auth 消息,直接发送业务帧(如订阅私有频道、触发删除操作);
- 服务端若依赖连接池管理会话,未鉴权连接会提前占用资源,造成 DoS 风险。
new WebSocket() 不支持传 headers,但可以绕过
标准浏览器 API 确实不接受 headers 参数,但有两类可行路径:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- URL 查询参数(
?token=xxx):兼容性最好,服务端从request.url或request.getParameterMap()解析,适合内部系统或短期 Token 场景; - 复用
Sec-WebSocket-Protocol头:它本用于协商子协议(如chat-v2),但可“借用”来传 Token(如Bearer xxx),服务端读req.headers['sec-websocket-protocol'],无需改代理配置; - 反向代理注入(Nginx / Traefik):前端仍用干净 URL,代理层根据 Cookie 或上游 Header 注入
Authorization,后端从 upgrade request 中读取 —— 这是最接近 REST 的做法,但需运维配合。
Token 必须带时效与吊销能力,不能复用登录态 JWT
把登录接口返回的长期 JWT 直接塞进 WebSocket URL,等于给攻击者一张“永久通行证”。正确做法是:
- 调用专用接口(如
/api/v1/ws-token)获取短期 Token,响应头设Cache-Control: no-store; - 该 Token 的
exp建议 ≤ 30 分钟,且服务端握手时必须校验 Redis 中是否已被主动吊销(如用户登出); - 避免存
localStorage,优先用httpOnlyCookie 管理主登录态,WS Token 仅内存暂存、用完即弃; - 若用 URL 方式,务必
encodeURIComponent(),否则特殊字符(如+、/)会导致解析失败。
真正容易被忽略的点:日志和代理层会完整记录 URL 中的 Token,哪怕只用一次,只要出现在 Nginx access_log 或浏览器地址栏历史里,就可能泄露。所以生产环境优先走 Sec-WebSocket-Protocol 或代理注入,而不是图省事拼 URL。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










