Protect Socket.IO Events with Rate Limiting
A real-time application can receive a large number of events from connected clients.
Without limits, a malicious or malfunctioning client may send excessive messages and consume server resources.
Rate limiting controls how frequently a client can perform an operation.
For example, a chat application might limit a user to five messages within a short time window.
You can implement basic per-socket rate limiting for a single server instance using an in-memory counter.
For multiple instances, use a shared rate-limit store such as Redis so that limits are consistent across servers.
An in-memory rate limiter works only inside one process and can grow indefinitely without cleanup. Use Redis or another shared store for reliable multi-instance rate limiting.
function createRateLimiter({ limit, windowMs }) {
const requests = new Map();
return function isAllowed(socketId) {
const now = Date.now();
const current = requests.get(socketId);
if (!current || now - current.start >= windowMs) {
requests.set(socketId, {
start: now,
count: 1
});
return true;
}
if (current.count >= limit) {
return false;
}
current.count += 1;
return true;
};
}
const allowMessage = createRateLimiter({
limit: 5,
windowMs: 10000
});
socket.on('chat:send', (payload, acknowledge) => {
if (!allowMessage(socket.id)) {
acknowledge?.({
success: false,
error: 'Too many messages. Please slow down.'
});
return;
}
// Continue with message validation and processing.
});Allows up to five events per socket within a ten-second window. This is a basic educational implementation and requires cleanup, memory controls, and shared storage for production.
Rate limiting protects the server from excessive events.
Per-socket limits are useful for basic applications.
Distributed applications require shared rate-limit storage.