Authentication and Session SecurityLesson 4.4
Rate limiting and account lockout to stop brute force attacks
brute force mechanics, rate limiting strategy, express-rate-limit, IP-based vs account-based limiting, lockout vs throttling, CAPTCHA, credential stuffing
Rate Limiting and Brute Force Protection
Brute force attacks try thousands of passwords against your login endpoint. Without rate limiting, an attacker can try millions of combinations per hour. Credential stuffing does the same with username/password pairs leaked from other breaches.
IP-Based Rate Limiting
const rateLimit = require('express-rate-limit');
// Strict limit on authentication endpoints
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10, // 10 attempts per IP per window
message: { error: 'Too many login attempts. Try again in 15 minutes.' },
standardHeaders: true,
legacyHeaders: false
});
app.post('/login', loginLimiter, loginHandler);
app.post('/forgot-password', loginLimiter, forgotPasswordHandler);Account-Based Throttling
// Track failed attempts per account in Redis or DB
async function checkLoginAttempts(email) {
const attempts = await redis.incr(`login:${email}`);
if (attempts === 1) await redis.expire(`login:${email}`, 900); // 15 min TTL
if (attempts > 5) {
const ttl = await redis.ttl(`login:${email}`);
throw new Error(`Account locked. Try again in ${ttl} seconds.`);
}
}
// On successful login:
await redis.del(`login:${email}`);Lockout vs Throttling
Hard lockout (block account after N failures) can be weaponized to DoS users by locking them out intentionally. Throttling (increasing delays) is safer. Combine IP-based rate limiting (stops bots) with per-account exponential backoff (stops targeted attacks).
