Real-Time Patterns and ArchitectureLesson 5.5
Rate limiting WebSocket connections and messages
connection rate limiting, per-client message rate limit, token bucket algorithm, sliding window counter, dropping vs queuing messages, abuse patterns, DDoS mitigation
WebSockets Are Easy to Abuse
A single client can open thousands of connections or flood the server with messages. Implement two layers of rate limiting:
// 1. Connection rate limit (use a Map per IP)
const connectionCounts = new Map();
wss.on('connection', (ws, req) => {
const ip = req.socket.remoteAddress;
const count = (connectionCounts.get(ip) || 0) + 1;
if (count > 5) {
ws.close(1008, 'Too many connections');
return;
}
connectionCounts.set(ip, count);
ws.on('close', () => {
connectionCounts.set(ip, connectionCounts.get(ip) - 1);
});
});// 2. Per-client message rate limit (token bucket)
wss.on('connection', (ws) => {
let tokens = 10;
const refill = setInterval(() => { tokens = Math.min(10, tokens + 2); }, 1000);
ws.on('message', (data) => {
if (tokens <= 0) {
ws.send(JSON.stringify({ type: 'error', code: 'RATE_LIMITED' }));
return;
}
tokens--;
handleMessage(data);
});
ws.on('close', () => clearInterval(refill));
});For production, use Redis-backed rate limiting so limits survive server restarts and apply across a cluster.
