跨站 websocket 劫持(cswsh)源于服务端未校验 origin 和身份凭证,防范需前后端协同:前端禁用 ws://、不泄露 token、连接后立即发认证帧;后端须在 upgrade 阶段校验 origin 白名单、验证 cookie 会话并绑定用户权限。

WebSocket 本身不强制执行同源策略,浏览器在发起连接时会自动带上 Origin 请求头,但服务端若不校验,攻击者就能从任意网页(比如恶意站点)悄悄建立连接,复用用户已登录的会话,从而读取或伪造实时消息——这就是跨站 WebSocket 劫持(CSWSH)。防范关键不在前端 JavaScript 做什么,而在于前后端协同把关;不过前端有几处必须配合的实操点。
前端必须指定合法 Origin 并避免暴露凭证
浏览器自动发送 Origin,你无需手动设置,但要确保页面本身来自可信域名(如 https://app.example.com),否则 Origin 值可能为空或不可信。同时注意:
- 不要把 token 拼在 WebSocket URL 里,例如
ws://api.example.com/ws?token=xxx—— 它会出现在浏览器地址栏、服务器日志、代理记录中,极易泄露 - 避免使用
file://协议调试,此时 Origin 为空,很多服务端校验会直接拒绝 - 生产环境务必用
wss://,禁用ws://;明文传输下,中间人可直接劫持连接
握手后立即发送认证帧,不依赖 URL 或初始请求
Origin 校验只管“谁连”,不管“谁在连”。前端应在连接成功后,第一时间发一条带身份凭证的消息,例如:
const ws = new WebSocket('wss://api.example.com/ws');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'auth',
token: getStoredToken() // 从 HttpOnly Cookie 或安全存储读取
}));
};
服务端收到该帧后验证 token 有效性,并将该 WebSocket 实例与用户会话绑定。未通过认证前,拒绝处理任何业务消息。
启用子协议(subprotocol)并和服务端对齐
这不是银弹,但能过滤掉大量非正规客户端(比如 curl 或简单脚本):
- 创建时显式声明:
new WebSocket('wss://...', ['myapp-v2']) - 服务端必须校验
Sec-WebSocket-Protocol头是否匹配预设值,不匹配就断连 - 子协议名应版本化(如
myapp-v2),便于后续灰度升级或淘汰旧客户端
配合后端完成完整防护链
前端无法单方面防住 CSWSH。你必须确认后端已做到以下几点:
- 在
upgrade阶段(而非connection事件)校验Origin,且只接受明确的 HTTPS 白名单(如https://app.example.com),拒绝*、模糊匹配或空 Origin - 握手请求携带了有效 Cookie,服务端据此验证 session 是否存在且未过期
- 每个连接生命周期内权限最小化,例如按用户角色限制可订阅的频道或操作类型
如果后端没做 Origin 校验,前端再规范也形同虚设。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











