WebSocket劫持(WebSocket Hijacking)漏洞与防护(进阶篇)
1. 漏洞描述
WebSocket劫持是一种利用WebSocket协议安全缺陷的攻击方式。攻击者通过窃取或伪造合法用户的WebSocket连接凭据(如会话Cookie、认证令牌等),冒用用户身份建立恶意WebSocket连接,从而实时窃取用户数据、注入恶意指令或执行未授权操作。与传统的HTTP会话劫持不同,WebSocket劫持直接发生在持久化的全双工通道上,危害更隐蔽且影响持续。
2. 漏洞原理深度剖析
2.1 WebSocket握手与身份验证机制
WebSocket连接通过HTTP/HTTPS协议发起“握手”升级请求。在握手请求中,浏览器会自动附加当前域下的Cookie、Authorization头等凭据。服务器基于这些凭据完成用户认证并建立连接。漏洞根源在于:
- 缺乏连接级认证:服务器仅在握手阶段验证凭据,后续通信帧中不再校验发送方身份。一旦握手成功,任何能向该连接发送帧的实体都被视为合法用户。
- 凭据泄露风险:若Cookie未设置HttpOnly、Secure等属性,或存在XSS漏洞,攻击者可轻易窃取凭据。
- 连接绑定不牢固:服务器未严格绑定WebSocket连接与底层传输层特征(如IP地址、TCP端口),导致连接可被劫持转移。
2.2 典型攻击场景
- 窃听与数据窃取:劫持连接后,攻击者实时接收服务器推送给用户的所有消息(如聊天内容、交易通知)。
- 命令注入:向服务器发送伪造的指令帧,冒充用户执行操作(如转账、修改设置)。
- 消息篡改与重放:拦截并篡改用户与服务器间的数据帧,或重放历史帧以触发重复操作。
3. 漏洞复现与演示
步骤1:环境搭建
假设有一个在线聊天应用,使用WebSocket(ws://chat.example.com/ws)。用户登录后,服务器返回会话Cookie session_id=abc123,并以此建立WebSocket连接。
步骤2:攻击者视角
- 凭据获取:通过XSS攻击窃取用户的
session_id(例如:document.cookie)。 - 连接建立:攻击者在自己的机器上运行脚本,使用窃取的Cookie发起WebSocket握手:
const ws = new WebSocket('ws://chat.example.com/ws'); ws.onopen = () => { // 握手成功,连接已被劫持 ws.send(JSON.stringify({type: "get_history"})); // 窃取聊天记录 }; - 持续监听:攻击者可保持连接开放,实时接收服务器推送的所有消息。
4. 进阶攻击手法
4.1 跨站WebSocket劫持(CSWSH)
类似CSRF,但针对WebSocket连接。若应用未验证WebSocket握手的Origin头,攻击者可在恶意网站中嵌入脚本,利用用户已登录状态自动建立WebSocket连接(浏览器自动发送Cookie)。攻击脚本示例:
<script>
const ws = new WebSocket('ws://vulnerable-app.com/ws');
ws.onopen = () => { ws.send(JSON.stringify({action: "delete_account"})); };
</script>
4.2 连接ID预测与暴力破解
某些应用使用可预测的连接标识符(如递增的ID)。攻击者枚举ID即可接入他人会话。例如:连接URL格式为ws://app.com/ws?conn_id=1001,攻击者遍历conn_id值即可劫持会话。
4.3 中间人(MitM)攻击
在未使用WSS(WebSocket over TLS)的情况下,攻击者可拦截明文握手请求,窃取Cookie或篡改握手数据。
5. 防护与缓解措施
5.1 强化身份验证机制
- 使用一次性令牌:在WebSocket握手请求的URL或自定义头中携带一次性令牌(如CSRF Token),服务器验证后立即失效。示例:
const token = getCSRFToken(); // 从页面meta标签获取 const ws = new WebSocket(`ws://app.com/ws?token=${token}`); - 双向认证:服务器在连接建立后,可要求客户端发送签名消息或重新认证。
5.2 严格校验握手请求
- 检查Origin头:验证握手请求的Origin头是否在白名单内,防止跨站请求。
- 验证Referer头(辅助手段):确保请求来自可信页面。
- 自定义协议头:添加自定义头(如
X-WebSocket-ID)并在服务器端校验,避免仅依赖Cookie。
5.3 绑定连接与会话
- 记录客户端特征:建立连接时,服务器记录客户端的IP、User-Agent等信息,后续收到帧时校验一致性。
- 使用信道绑定令牌:将会话与底层TLS通道绑定(如
tls-unique),防止连接被迁移。
5.4 安全配置与编码
- 强制使用WSS:生产环境必须使用TLS加密,防止窃听与篡改。
- 设置Cookie属性:会话Cookie应设置
HttpOnly、Secure、SameSite=Strict。 - 帧级校验:在关键业务帧中加入消息签名或MAC(消息认证码),确保帧的完整性与来源可信。
5.5 连接生命周期管理
- 超时与心跳:若连接长时间无活动,强制断开并清理会话。
- 单一连接限制:同一用户只允许一个活跃WebSocket连接,新连接建立时旧连接自动失效。
6. 安全测试与验证
- 使用Burp Suite的WebSocket客户端工具,尝试修改握手请求的Origin、Cookie等字段,验证服务器是否拒绝。
- 编写自动化脚本模拟CSWSH攻击,检查应用是否校验Origin。
- 审计代码,确保所有WebSocket消息处理函数都验证了用户权限与上下文。
总结:WebSocket劫持的核心风险在于连接身份持续性问题。防护需围绕“强化握手认证、绑定连接特征、加密通信信道、实施帧级安全”四层纵深防御展开,结合业务场景设计恰当的认证与审计机制,确保全双工通道的端到端安全。