10. Security Considerations (安全考虑)
WebSocket协议的设计考虑了多种安全威胁。本章描述了主要的安全考虑和建议的缓解措施。
10.1 Non-Browser Clients (非浏览器客户端)
WebSocket协议可以被任何客户端使用,不仅限于Web浏览器。非浏览器客户端没有浏览器的同源策略保护。
风险:
- 可以伪造Origin头部
- 可以绕过CORS限制
- 可以发起大量连接
缓解措施:
- 服务器端必须 (MUST) 实施额外的身份验证
- 使用令牌验证(如JWT)
- 实施速率限制
- 验证所有输入数据
// 服务器端验证示例
function verifyClient(info, callback) {
// 验证Origin
const allowedOrigins = ['https://example.com'];
if (!allowedOrigins.includes(info.origin)) {
callback(false, 403, 'Forbidden');
return;
}
// 验证Token
const token = info.req.url.split('?token=')[1];
if (!isValidToken(token)) {
callback(false, 401, 'Unauthorized');
return;
}
callback(true);
}
10.2 Origin Considerations (源考虑)
Origin头部是关键的安全机制。
推荐做法:
-
验证Origin: 服务器应该 (SHOULD) 验证Origin头部
const allowedOrigins = [
'https://example.com',
'https://app.example.com'
];
if (!allowedOrigins.includes(request.headers.origin)) {
response.status(403).send('Origin not allowed');
} -
白名单方式: 使用白名单而不是黑名单
-
动态Origin: 如果需要支持动态Origin,使用数据库配置
注意: 非浏览器客户端可以伪造Origin,因此不应单独依赖Origin验证。
10.3 Attacks On Infrastructure (基础设施攻击)
缓存投毒攻击
WebSocket使用掩码机制来防止缓存投毒:
- 客户端到服务器的所有帧必须 (MUST) 掩码
- 服务器到客户端的帧禁止 (MUST NOT) 掩码
- 使用随机掩码密钥
中间人攻击
风险:
- 未加密连接容易被拦截
- 数据可以被读取和修改
缓解措施:
- 使用wss:// (TLS加密)
- 验证服务器证书
- 实施证书固定 (Certificate Pinning)
// 浏览器端:始终使用wss://
const ws = new WebSocket('wss://example.com/socket');
// 服务器端:强制使用TLS
if (!request.connection.encrypted) {
response.status(403).send('TLS required');
}
10.4 Implementation-Specific Limits (实现特定的限制)
实现应该 (SHOULD) 设置合理的限制以防止资源耗尽攻击。
推荐的限制
1. 消息大小限制
const MAX_MESSAGE_SIZE = 1024 * 1024; // 1MB
ws.on('message', (data) => {
if (data.length > MAX_MESSAGE_SIZE) {
ws.close(1009, 'Message too big');
}
});
2. 连接数限制
const MAX_CONNECTIONS = 10000;
const connections = new Set();
function acceptConnection(ws) {
if (connections.size >= MAX_CONNECTIONS) {
ws.close(1008, 'Server overloaded');
return false;
}
connections.add(ws);
return true;
}
3. 消息频率限制
const RATE_LIMIT = 100; // 每秒100条消息
const messageCount = new Map();
function checkRateLimit(clientId) {
const count = messageCount.get(clientId) || 0;
if (count > RATE_LIMIT) {
return false;
}
messageCount.set(clientId, count + 1);
return true;
}
4. 帧大小限制
- 限制单个帧的最大大小
- 限制分片消息的最大帧数
10.5 WebSocket Client Authentication (WebSocket客户端身份验证)
认证方法
1. 握手时的Cookie认证
// 客户端:Cookie会自动发送
const ws = new WebSocket('wss://example.com/socket');
// 服务器端:验证Cookie
ws.on('connection', (ws, request) => {
const cookies = parseCookies(request.headers.cookie);
if (!isValidSession(cookies.sessionId)) {
ws.close(1008, 'Unauthorized');
}
});
2. URL参数中的Token
const token = generateToken();
const ws = new WebSocket(`wss://example.com/socket?token=${token}`);
3. 首条消息认证
ws.on('connection', (ws) => {
let authenticated = false;
ws.on('message', (data) => {
if (!authenticated) {
const auth = JSON.parse(data);
authenticated = verifyToken(auth.token);
if (!authenticated) {
ws.close(1008, 'Authentication failed');
}
return;
}
// 处理正常消息
});
});
4. 自定义握手头部
const ws = new WebSocket('wss://example.com/socket', {
headers: {
'Authorization': 'Bearer ' + token
}
});
10.6 Connection Confidentiality and Integrity (连接机密性和完整性)
TLS/SSL要求
生产环境必须 (MUST) 使用wss://:
✅ TLS的优势:
- 加密所有传输数据
- 防止窃听
- 防止数据篡改
- 服务器身份验证
❌ ws://的风险:
- 明文传输
- 容易被拦截
- 无法验证服务器身份
配置示例
// Node.js服务器端
const https = require('https');
const WebSocket = require('ws');
const fs = require('fs');
const server = https.createServer({
cert: fs.readFileSync('/path/to/cert.pem'),
key: fs.readFileSync('/path/to/key.pem'),
// 推荐的TLS配置
ciphers: 'ECDHE-RSA-AES128-GCM-SHA256:...',
honorCipherOrder: true,
minVersion: 'TLSv1.2'
});
const wss = new WebSocket.Server({ server });
server.listen(443);
10.7 Handling of Invalid Data (处理无效数据)
实现必须 (MUST) 正确处理无效数据,防止安全漏洞。
无效UTF-8文本
function isValidUTF8(buffer) {
try {
buffer.toString('utf8');
return true;
} catch (e) {
return false;
}
}
ws.on('message', (data, isBinary) => {
if (!isBinary && !isValidUTF8(data)) {
ws.close(1007, 'Invalid UTF-8');
}
});
协议违规
当检测到协议违规时,必须 (MUST) 关闭连接:
- 服务器收到未掩码的客户端帧
- 客户端收到掩码的服务器帧
- 收到无效的Opcode
- 收到分片的控制帧
- 收到超过125字节的控制帧
10.8 Use of SHA-1 by the WebSocket Handshake (WebSocket握手使用SHA-1)
握手使用SHA-1哈希算法。虽然SHA-1已知有碰撞攻击,但在握手上下文中是安全的:
为什么安全:
- 不用于加密或签名
- 仅用于握手验证
- 攻击者无法利用碰撞
- 有固定的GUID字符串
未来考虑:
- 可能在未来版本中使用更强的哈希
- 当前版本继续使用SHA-1
安全检查清单
实施WebSocket服务时应检查:
- 使用wss://(TLS)而非ws://
- 验证Origin头部
- 实施身份验证和授权
- 设置消息大小限制
- 设置连接数限制
- 实施速率限制
- 验证所有输入数据
- 正确处理协议违规
- 记录安全事件
- 定期更新TLS配置
- 监控异常连接模式
- 实施超时机制
参考资源
- OWASP WebSocket Security: https://owasp.org/www-community/vulnerabilities/WebSocket_security
- RFC 8446: TLS 1.3
- RFC 6455: WebSocket Protocol ← 本文档
参考链接
- 上一章: 9. Extensions
- 下一章: 11. IANA Considerations
- 实现指南: 安全考虑要点