Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion backend/src/lib/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]] : [];

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -189,4 +225,4 @@ io.on("connection", (socket) => {
});
});

export { io, app, server };
export { io, app, server };
Loading