patterntypescriptMajor
Rate Limiting Real-Time Events Per Client Prevents WebSocket Abuse
Viewed 0 times
rate limitingtoken bucketWebSocket abuseper connectionmessage ratepolicy violationDoS prevention
Problem
A WebSocket server accepts messages from clients without rate limiting. A malicious or buggy client sends thousands of messages per second, consuming CPU and memory and degrading the experience for all other clients.
Solution
Implement a per-connection token bucket rate limiter. If a client exceeds the rate limit, drop messages or close the connection with a policy violation code.
class TokenBucket {
private tokens: number;
private lastRefill: number;
constructor(
private capacity: number,
private refillRate: number // tokens per ms
) {
this.tokens = capacity;
this.lastRefill = Date.now();
}
consume(n = 1): boolean {
const now = Date.now();
const elapsed = now - this.lastRefill;
this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillRate);
this.lastRefill = now;
if (this.tokens >= n) {
this.tokens -= n;
return true;
}
return false;
}
}
// Per-connection rate limiter: 50 messages/second, burst of 100
wss.on('connection', (ws) => {
const limiter = new TokenBucket(100, 50 / 1000);
ws.on('message', (data) => {
if (!limiter.consume()) {
ws.send(JSON.stringify({ error: 'rate_limited' }));
return;
}
handleMessage(ws, data);
});
});Why
WebSocket servers have no built-in rate limiting. Unlike HTTP, where each request is a separate connection, a single WebSocket client can send unbounded messages over one long-lived connection. Without a gate, one client can monopolize the server.
Gotchas
- Rate limit by user identity (from auth token), not just by connection — a user can open multiple connections.
- Close the connection (code 1008 - policy violation) after repeated rate limit violations, not just warn.
- Different message types may warrant different rate limits — cursor updates vs chat messages.
- Use Redis counters (INCR + EXPIRE) for rate limiting across multiple server instances.
Revisions (0)
No revisions yet.