In this lesson, you will learn how to define and implement secure thresholds to block malicious actors from brute-forcing user accounts or overloading your authentication services.
Why Lockout Policies Matter
When an attacker attempts to guess a password, they perform a "brute-force" or "dictionary" attack. Without a lockout policy, an attacker can make thousands of requests per minute. By implementing thresholds, we force a "cooling-off" period, significantly reducing the success probability of automated attacks.
Defining Your Thresholds
A robust policy generally relies on two dimensions: Account-level lockouts and IP-based rate limiting.
- Account-level: If a specific account fails login X times, block access to that account for Y minutes.
- IP-level: If a single IP address triggers too many failed logins across any accounts, block that IP temporarily.
Implementation Logic
In Node.js, you should maintain a count of failures in a fast, in-memory store like Redis. Avoid writing these to your primary database on every failed attempt to prevent performance bottlenecks.
// Conceptual logic for a login attempt
async function handleLogin(username, ip) {
const accountKey = `lockout:user:${username}`;
const ipKey = `lockout:ip:${ip}`;
const [accountAttempts, ipAttempts] = await redis.mget(accountKey, ipKey);
if (accountAttempts >= 5 || ipAttempts >= 20) {
throw new Error("Too many attempts. Please try again in 15 minutes.");
}
const isValid = await verifyPassword(username);
if (!isValid) {
await redis.multi()
.incr(accountKey).expire(accountKey, 900)
.incr(ipKey).expire(ipKey, 900)
.exec();
throw new Error("Invalid credentials.");
}
// Clear counters on successful login
await redis.del(accountKey);
}
Critical Considerations
- Exponential Backoff: Instead of a fixed 15-minute lock, consider increasing the duration after each subsequent violation.
- Informative, but Safe: Your error message should be helpful to the user (e.g., "Account locked due to multiple failed attempts") without leaking information about whether the username actually exists in your system (mitigating enumeration attacks).
- Graceful Unlock: Always provide an "Unlock" path, such as an email verification link or a time-based auto-unlock, to prevent permanent denial-of-service on legitimate users.
Key Takeaway: Implement both per-account and per-IP thresholds to defend against targeted brute-force attacks while preserving system availability.