JAVASCRIPT

Implement Brute-Force Protection for Login Attempts

Secure user accounts by implementing a custom rate-limiting mechanism for failed login attempts to prevent brute-force attacks in Node.js.

const express = require('express');
const app = express();
const bodyParser = require('body-parser');

app.use(bodyParser.json());

// In-memory store for failed login attempts (in a real app, use Redis/database)
const loginAttempts = new Map(); // Stores { username: { count: number, lastAttempt: Date, blockedUntil: Date } }
const MAX_FAILED_ATTEMPTS = 5;
const BLOCK_DURATION_MS = 60 * 1000; // Block for 1 minute

function checkLoginAttempts(username) {
    const userAttempts = loginAttempts.get(username);

    if (userAttempts && userAttempts.blockedUntil && userAttempts.blockedUntil > new Date()) {
        return { allowed: false, remaining: 0, blockedUntil: userAttempts.blockedUntil };
    }

    return { allowed: true, remaining: MAX_FAILED_ATTEMPTS - (userAttempts ? userAttempts.count : 0) };
}

function recordFailedAttempt(username) {
    const now = new Date();
    let userAttempts = loginAttempts.get(username) || { count: 0, lastAttempt: now };

    userAttempts.count++;
    userAttempts.lastAttempt = now;

    if (userAttempts.count >= MAX_FAILED_ATTEMPTS) {
        userAttempts.blockedUntil = new Date(now.getTime() + BLOCK_DURATION_MS);
        userAttempts.count = 0; // Reset count after blocking for the next cycle
        console.warn(`User ${username} blocked for ${BLOCK_DURATION_MS / 1000} seconds due to too many failed attempts.`);
    }

    loginAttempts.set(username, userAttempts);
}

function resetLoginAttempts(username) {
    loginAttempts.delete(username);
}

// Simulate user database
const users = { 'admin': 'password123', 'testuser': 'securepass' };

app.post('/login', (req, res) => {
    const { username, password } = req.body;

    if (!username || !password) {
        return res.status(400).json({ message: 'Username and password are required.' });
    }

    const attemptStatus = checkLoginAttempts(username);
    if (!attemptStatus.allowed) {
        const timeRemaining = Math.ceil((attemptStatus.blockedUntil.getTime() - new Date().getTime()) / 1000);
        return res.status(429).json({ message: `Too many failed login attempts. Please try again in ${timeRemaining} seconds.` });
    }

    if (users[username] && users[username] === password) { // In real app, use bcrypt.compare
        resetLoginAttempts(username);
        res.json({ message: 'Login successful!' });
    } else {
        recordFailedAttempt(username);
        const newAttemptStatus = checkLoginAttempts(username);
        let message = 'Invalid username or password.';
        if (!newAttemptStatus.allowed) {
            const timeRemaining = Math.ceil((newAttemptStatus.blockedUntil.getTime() - new Date().getTime()) / 1000);
            message = `Invalid username or password. You have been temporarily blocked. Try again in ${timeRemaining} seconds.`;
        } else if (newAttemptStatus.remaining <= MAX_FAILED_ATTEMPTS / 2) { // Give a hint without revealing exact count
            message = `Invalid username or password. You have ${newAttemptStatus.remaining} attempts remaining before temporary block.`;
        }
        res.status(401).json({ message });
    }
});

app.listen(3000, () => {
    console.log('Server running on port 3000');
});
How it works: This Node.js Express snippet implements a custom brute-force protection mechanism specifically for login attempts. It tracks failed attempts for each username (using an in-memory Map, but a robust solution would use Redis or a database). If a user exceeds 'MAX_FAILED_ATTEMPTS' within a certain period, their account (or IP, depending on implementation) is temporarily 'blocked' for 'BLOCK_DURATION_MS'. This prevents attackers from rapidly guessing passwords. The 'checkLoginAttempts' function determines if a login is allowed, and 'recordFailedAttempt' updates the attempt count and applies blocks. On successful login, attempts are reset. This helps protect user accounts from dictionary and brute-force attacks without impacting legitimate users too severely.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs