diff --git a/backend/src/lib/socket.js b/backend/src/lib/socket.js index 92f5f85..3a772d9 100644 --- a/backend/src/lib/socket.js +++ b/backend/src/lib/socket.js @@ -39,6 +39,12 @@ io.use((socket, next) => { const userSocketMap = {}; +// SECURITY ENGINE: In-memory store for tracking sliding window handshake intervals +const connectionRates = {}; +const MAX_CONNECTIONS_PER_WINDOW = 5; +const RATE_LIMIT_WINDOW_MS = 10000; // 10-second sliding window + +export const getReceiverSocketIds = (userId) => userSocketMap[userId] || []; export const getReceiverSocketIds = (userId) => userSocketMap[userId] ? [...userSocketMap[userId]] : []; @@ -70,6 +76,36 @@ const canCommunicate = async (senderId, receiverId) => { } }; +/** + * SOCKET MIDDLEWARE: IP-Based Connection Rate Limiter + * Intercepts incoming client handshakes prior to connection establishment. + * Safely mitigates script-based resource exhaustion or socket flooding attacks. + */ +io.use((socket, next) => { + // Safely extract client IP checking proxy layers first + const clientIp = socket.handshake.headers['x-forwarded-for'] || socket.handshake.address; + const currentTime = Date.now(); + + if (!connectionRates[clientIp]) { + connectionRates[clientIp] = []; + } + + // Retain only connection timestamps within the active 10-second window + connectionRates[clientIp] = connectionRates[clientIp].filter( + (timestamp) => currentTime - timestamp < RATE_LIMIT_WINDOW_MS + ); + + // Drop handshakes immediately if they exceed thresholds + if (connectionRates[clientIp].length >= MAX_CONNECTIONS_PER_WINDOW) { + console.warn(`WebSocket Rate Limit Breached: Blocked connection from IP ${clientIp}`); + return next(new Error("Too many connection requests. Please slow down.")); + } + + // Log the current valid handshake timestamp and let the client pass through + connectionRates[clientIp].push(currentTime); + next(); +}); + io.on("connection", (socket) => { const getActiveContacts = async (userId) => { try { @@ -189,4 +225,4 @@ io.on("connection", (socket) => { }); }); -export { io, app, server }; +export { io, app, server }; \ No newline at end of file