KAHIBARO
Discord Login Register

15.8. Brute-Force Protection

Understanding Brute-Force Attacks

Brute-force attacks are attempts to guess secrets by trying many possibilities until one works. In backend systems this almost always means:

The attacker automates requests and keeps trying. If you do not detect and slow them down, they can send thousands or millions of attempts.

Typical brute-force patterns:

You must design your backend so that these attacks are detected, limited, and expensive for attackers, while still being usable for real users.

Brute-force protection is not optional on any login, password reset, or token-based endpoint that is exposed to the internet.

In this chapter we focus on protection strategies, not on basic authentication concepts, which are covered elsewhere.


Threat Models and Targets

Online vs Offline Brute Force

There are two major brute-force scenarios:

Online brute force

The attacker sends requests to your live backend:

This chapter focuses mainly on online brute-force protection.

Offline brute force

The attacker gets a copy of password hashes or tokens and tries to crack them offline:

Offline brute-force resistance is mainly achieved by secure password hashing (covered in another chapter), but your online protections still matter because they reduce the chance that attackers can obtain credentials in the first place.

Common Attack Targets

Typical endpoints that need protection:

Endpoint typeExamples
Login/login, /auth/token, /api/auth/login
Password reset/password/forgot, /password/reset
Account recovery / unlock/account/recovery, /unlock
2FA / OTP verification/2fa/verify, /otp/check
Signup (abuse control)/register, /signup
Token verification/verify-email, /magic-link, /invite
API key use/api/* with Authorization headers

Attacker goals:

Core Brute-Force Protection Concepts

Three Main Levers

You protect against brute force by combining these three ideas:

  1. Detection
    Notice suspicious patterns:
    • too many failed attempts per IP
    • too many failed attempts per user
    • too many attempts across the whole system
  2. Limiting speed
    Slow or block attackers:
    • rate limits
    • temporary blocks
    • longer delays after each failure
  3. Improving guesses’ effectiveness
    Reduce value of each guess:
    • strong password rules and password managers
    • 2FA so password alone is not enough
    • single-use, short-lived tokens for sensitive actions

Do not rely on a single control. Robust protection comes from layers: rate limits, IP tracking, account tracking, lockouts, delays, and strong credential handling.


Simple Rate Limiting

What Is Rate Limiting?

Rate limiting puts a cap on how many requests are allowed in a period.

Examples:

If the limit is exceeded, you return a response such as:

Rate limiting does not stop all brute force attempts, but it makes attacks slower and more expensive.

Fixed Window vs Sliding Window

Two common rate limit algorithms:

AlgorithmHow it worksProsCons
Fixed windowCount requests in fixed intervals, such as each minuteSimple to implementBursts allowed at window edges
Sliding windowCount requests over a moving time window, such as last 60sSmoother, fairer limitingSlightly more complex

For example, with a limit of 10 requests per minute:

Example: IP-Based Rate Limit

Imagine an endpoint /auth/login. You might implement:

Pseudo-logic:

text
key = "login:ip:" + client_ip
current = GET(key)  // from Redis
if current >= 10 in last 60 seconds:
    return 429 Too Many Requests
INCR(key)
EXPIRE key in 60 seconds

This uses a cache such as Redis to track counts.

Why IP-based only is not enough

Attackers use:

So you must also track per-account failures.


Account-Based Protections

Tracking Failed Logins Per Account

You should record failed login attempts per username or email, not just per IP.

Example rules:

Simplified data:

Account (email)FailuresLast failureStatus
alice@example.com0n/aactive
bob@example.com42026-08-27 10:01:12active
eve@example.com112026-08-27 09:59:48locked 15m

You can store:

Temporary Account Lockout

A temporary lockout makes brute-force attacks harder.

Example policy:

Pseudo-logic:

text
if now < user.lockout_until:
    return 423 Locked  // or 429, or 403
if password_correct:
    reset failed_login_count
    user.lockout_until = null
    log login success
    return success
else:
    increment failed_login_count
    if failed_login_count >= 5:
        user.lockout_until = now + 15 minutes
    log login failure
    return error

Balancing security and usability

Too aggressive lockouts can allow attackers to:

To reduce abuse:

Progressive Delays and Backoff

Why Use Delays?

A simple lockout might be too strict. Instead, you can slow each additional attempt.

For example:

This is called progressive backoff.

Progressive delays can slow attackers without completely blocking legitimate users who mistype their password a few times.

Example Backoff Strategy

You can use an exponential formula:

$$
\text{delay\_seconds} = \min(2^{n-1}, 60)
$$

Where:

Table:

Fail count (n)Delay formulaDelay (seconds)
1$2^{0}$1
2$2^{1}$2
3$2^{2}$4
4$2^{3}$8
5$2^{4}$16
6$2^{5}$32
7+min($2^{6}$, 60)60

Implementation idea:

  1. Track consecutive failures since last success.
  2. Before checking the password, compute the delay.
  3. Sleep for the delay.
  4. Then continue.

Note: Use server-side sleep carefully so you do not block worker threads. In async frameworks, use non-blocking sleep.


IP-Based and Network-Level Protections

IP Rate Limits

As mentioned earlier, IP-based limits are a first layer:

They protect against single hosts and against some abuse from common proxies.

IP Reputation and Blocking

Some systems integrate with IP reputation lists or maintain internal IP blacklists.

Possible actions:

Country or ASN based rules

You might add stricter limits for:

Be careful to avoid unfairly blocking legitimate users.

Network-Level Tools

Web servers, proxies, and firewalls often have built-in protections:

It is a good idea to:

This gives redundancy. If one layer fails, the other still protects you.


CAPTCHA and User Interaction Checks

When to Use a CAPTCHA

A CAPTCHA tries to separate humans from bots.

You might require a CAPTCHA:

Approach:

Implementation Pattern

  1. User fails login 3 times.
  2. On next login attempt, the frontend displays a CAPTCHA challenge.
  3. Backend verifies the CAPTCHA token with the CAPTCHA provider.
  4. Backend checks password only if CAPTCHA is valid.

Example login flow:

text
POST /auth/login
Body: { "email": "...", "password": "...", "captcha_token": "..." }
1. Check if account is in "captcha required" mode.
2. If yes, verify captcha_token with provider.
3. If CAPTCHA fails, return error.
4. If CAPTCHA passes, proceed with normal login checks.

Some systems also use invisible or risk-based CAPTCHAs that do not always require explicit user input.


Credential Stuffing and Password Reuse

What Is Credential Stuffing?

Attackers often use username/password pairs stolen from other websites and try them on your site.

Pattern:

Credential stuffing is related to brute-force attacks, but instead of random passwords, they use likely passwords, which increases success rate.

Defenses Against Credential Stuffing

Key strategies:

  1. Rate limiting
    • Per account and IP, as before.
  2. Known password checks
    • Check passwords against known breached password lists, for example "Have I Been Pwned" API, at password change or registration.
    • Reject obviously compromised passwords.
  3. 2FA / MFA
    • Even if password is correct, login still requires time-based code or hardware token.
  4. Suspicious login detection
    • New device, unusual location, or impossible travel.
    • Trigger additional verification steps, such as email code.
  5. Login alerts
    • Notify users by email when login from a new country, device, or IP occurs.

Password reuse makes brute-force and credential stuffing far more dangerous. Encourage and support password managers and strong unique passwords.


Protecting One-Time Codes and Tokens

Brute-force is not only about passwords. Any short code or token can be guessed if not protected.

One-Time Passwords (OTP) and SMS/Email Codes

Typical codes:

If an attacker can try many codes, they will eventually guess correctly.

Example risk

Best Practices for OTPs

  1. Short lifetime
    • Codes expire quickly, for example 5 to 10 minutes.
  2. Use once
    • Once a code is used successfully, it becomes invalid immediately.
  3. Attempt limits
    • Limit number of tries, for example 3 to 5 attempts per code.
  4. Per user and per IP tracking
    • Lock further attempts for some time if too many failures occur.

Example: Confirming 2FA Code

Flow:

  1. User enters code from their authenticator app.
  2. Backend checks:
    • Is the account locked for 2FA attempts?
    • Has there been too many recent failures?
    • Does the code match the expected TOTP for this time?
  3. If correct:
    • Mark login as fully authenticated.
    • Reset 2FA failure counter.
  4. If incorrect:
    • Increment 2FA failure counter.
    • Possibly add delay or temporarily lock further attempts.

Handling Error Messages and Enumeration

Avoid User Enumeration

Brute-forcing credentials often begins with identifying valid accounts.

Do not reveal whether an account exists. For example:

Same rule for:

Error messages should avoid confirming whether a username or email exists in your system.

Consistent Response Times

Attackers can also detect valid accounts by:

Example:

Aim for:

Sometimes you can:

Logging, Monitoring, and Alerting

What to Log

To detect brute-force attacks, log at least:

Avoid logging passwords, codes, or full tokens.

Example Log Entry

json
{
  "event": "login_failed",
  "email": "alice@example.com",
  "ip": "203.0.113.45",
  "user_agent": "Mozilla/5.0 ...",
  "reason": "invalid_password",
  "failed_count": 4,
  "lockout_until": null,
  "timestamp": "2026-08-27T10:15:23Z"
}

Monitoring and Alerts

You can configure alerts for:

Use tools covered elsewhere in logging and monitoring chapters, such as:

Practical Design Guidelines

Combine Multiple Controls

A practical brute-force protection setup might include:

  1. Per IP rate limiting on login and reset endpoints
  2. Per account failure tracking and temporary lockouts
  3. Progressive delays after repeated failures
  4. CAPTCHA after several failures or for untrusted traffic
  5. Short-lived and single-use codes with attempt limits
  6. Consistent error messages regardless of account existence
  7. Two-factor authentication for higher-value accounts
  8. Monitoring and alerting based on logs and metrics

Example Policy for a Typical Web App

For a normal consumer application, you might choose:

These numbers are just examples. In real systems, you must tune them based on your user base and risk level.


Trade-offs and Pitfalls

Denial of Service via Lockouts

If you lock accounts too aggressively:

Mitigation strategies:

Shared IPs and NAT

Many users may share one IP:

If your per IP limits are too strict, you might block many legitimate users at once.

Mitigation strategies:

Bot Evasion

Advanced bots can:

So you cannot rely on only one type of control. This is why the defense in depth idea is critical.


Summary

Brute-force protection is about making repeated guessing:

Key elements:

By thoughtfully combining these techniques, you significantly reduce the risk that attackers can break into accounts through brute-force or credential stuffing attacks, while keeping your application usable for real users.

Views: 9

Comments

Please login to add a comment.

Don't have an account? Register now!