← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Brute-Force Protection

debt(d5/e5/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list Semgrep as the tool, with a specific code pattern targeting login/authenticate methods missing a rate-limit check before password_verify(). This is not a default linter check but requires a specialist SAST rule, and the absence of protection is silent in production until attacks occur — Semgrep brings it to d5 rather than d7/d9.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix requires adding a Redis-backed attempt counter keyed by username, configuring block durations, and then applying the same logic to password-reset endpoints. This spans at least authentication, password-reset, and infrastructure/cache layers — more than a single-line patch (e1/e3) but not a full architectural rework (e7+).

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Brute-force protection must be consistently applied across all authentication surfaces (login, password reset, MFA). Every new authentication-adjacent feature must be reviewed to ensure the rate-limiting layer is present, creating an ongoing maintenance obligation across multiple workstreams without necessarily defining the entire system's shape.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The canonical misconception is that IP-based rate limiting alone is sufficient, which is exactly what most developers naturally reach for first (mirroring how general API rate limiting works). The per-account attempt counting requirement contradicts the intuitive IP-centric mental model, and the common_mistakes list reveals multiple serious non-obvious failure modes: permanent lockout as a DoS vector, unprotected reset endpoints, and username enumeration via error messages.

About DEBT scoring →

Also Known As

rate limiting login account lockout credential stuffing defence login throttling

TL;DR

Defences against automated credential-guessing attacks — rate limiting login attempts, account lockout, CAPTCHA, and multi-factor authentication to make guessing passwords computationally infeasible.

Explanation

Brute-force attacks submit large volumes of credential combinations to authentication endpoints until one succeeds. Defence layers: (1) Rate limiting — restrict attempts per IP and per account (e.g. 5 failures per 10 minutes) using a token-bucket or sliding-window counter stored in Redis or APCu. (2) Progressive delays — exponential back-off after each failure slows automated tools without locking legitimate users out permanently. (3) Account lockout — temporarily disable an account after N failures; prefer time-based lockout over permanent to avoid denial-of-service. (4) CAPTCHA — challenges that are easy for humans and hard for bots, triggered after a threshold of failures. (5) MFA — a second factor renders the guessed password alone useless. In PHP, rate limiting is typically implemented in middleware or a firewall layer before the authentication logic. Credential stuffing (using breached credential databases) is a variant — defeated by checking submitted passwords against known-breached lists (HaveIBeenPwned API). Timing-safe comparison (hash_equals) prevents timing-based oracle attacks that can leak valid usernames.

Watch Out

Lockout policies must account for distributed attacks — if an attacker knows a username they can intentionally trigger lockouts to deny service to legitimate users. Consider CAPTCHA escalation over hard lockout.

Common Misconception

IP-based rate limiting alone is not sufficient — distributed botnets rotate IPs, so per-account attempt counting is essential alongside per-IP limits.

Why It Matters

Authentication endpoints are among the most frequently targeted surfaces on the web — without brute-force protection, weak or reused passwords are cracked in minutes by automated tools.

Common Mistakes

  • Rate limiting only by IP — attackers distribute requests across thousands of IPs; always also count per-username.
  • Permanent account lockout — creates a denial-of-service vector where an attacker locks every account by deliberate failures.
  • Not applying rate limits to password-reset endpoints — reset flows are equally brute-forceable and often less protected.
  • Leaking whether a username exists via different error messages — use a generic 'invalid credentials' message regardless of which field is wrong.

Code Examples

💡 Note
The bad example allows unlimited attempts. The fix tracks failures per hashed email in Redis with a 15-minute TTL — the counter resets on success and the same generic exception message is used for both 'user not found' and 'wrong password' to prevent username enumeration.
✗ Vulnerable
// No rate limiting — unlimited attempts:
public function login(string $email, string $password): bool {
    $user = User::findByEmail($email);
    return $user && password_verify($password, $user->password_hash);
}
✓ Fixed
// Redis-backed per-account rate limit:
public function login(string $email, string $password): bool {
    $key = 'login_attempts:' . hash('sha256', $email);
    $attempts = (int) $this->redis->get($key);
    if ($attempts >= 5) {
        throw new TooManyAttemptsException('Account temporarily locked');
    }
    $user = User::findByEmail($email);
    if (!$user || !password_verify($password, $user->password_hash)) {
        $this->redis->incr($key);
        $this->redis->expire($key, 900); // 15 min window
        throw new InvalidCredentialsException('Invalid credentials');
    }
    $this->redis->del($key); // reset on success
    return true;
}

Added 10 Apr 2026
Views 116
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
3 pings F 0 pings S 0 pings S 3 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S
No pings yet today
Ahrefs 1
SEMrush 9 Google 7 ChatGPT 6 Ahrefs 6 PetalBot 6 Scrapy 4 Perplexity 3 Claude 3 Bing 3 Brave Search 3 Meta AI 2 Twitter/X 2 Applebot 2 Unknown AI 1 Majestic 1 Sogou 1
crawler 55 crawler_json 4
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
Two-Factor Authentication (2FA) security Two-factor authentication requires two different types of proof to verify your identity—typically something you know (password) plus something you have (phone) or something you are (fingerprint).

Passwords get stolen constantly through phishing, breaches, and weak choices. 2FA means a stolen password alone isn't enough—attackers need physical access to your phone or hardware key, dramatically reducing successful account compromises.

💡 Enable 2FA on every account that offers it, and prefer authenticator apps over SMS whenever possible.

Ask Codex about Two-Factor Authentication (2FA) →
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Add a Redis-backed attempt counter keyed by username; block for 15 minutes after 5 failures; apply the same limit to password-reset endpoints
🔗 Prerequisites
🔍 Detection Hints
login or authenticate method with no rate-limit check before password_verify()
Auto-detectable: ✓ Yes semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: High Context: Function Tests: Update
CWE-307 CWE-799 CWE-308


✓ schema.org compliant