Humans Only Humans Only
Humans Only Humans Only

How to prevent brute force attacks (without wrecking your login UX)

Published on 2026-02-19

A practical playbook for product owners and developers: throttle intelligently, step up when it’s suspicious, and keep real users moving.

How to prevent brute force attacks (without wrecking your login UX) visual #1

Brute force attacks: what you’re actually dealing with

A brute force attack is an automated attempt to guess credentials by trying lots of passwords (or lots of usernames) until something works. In practice, it shows up as high-volume failed logins, password spraying (“one common password across many accounts”), or distributed attempts across many IPs.

OWASP’s guidance puts it plainly: you can’t “solve” brute force forever, but you can make it expensive, slow, and visible enough that it stops being profitable (OWASP: Blocking Brute Force Attacks).

The goal: prevent brute force attacks without turning login into a project

Product owners usually want two outcomes: fewer compromised accounts and no conversion cliff. Developers want something enforceable at the edge of POST /login that won’t melt under load.

The most reliable way to prevent brute force attacks is to combine three things:

  1. Rate limiting (throttling attempts)
  2. Risk-based human verification (step-up only when needed)
  3. Stronger authentication (MFA/passkeys where it counts)

NIST explicitly calls for rate limiting to constrain failed authentication attempts (NIST SP 800-63B). That’s your baseline.

A practical model that scales: Detect → Decide → Respond

If you only ship one pattern, ship this. It keeps product and engineering aligned, and it’s easy to tune from real traffic.

  1. Detect signals: velocity, repeated failures, suspicious networks, new devices, impossible travel.
  2. Decide a risk outcome for this attempt.
  3. Respond with Allow / Step-up / Block (or throttle).

This is how you stop brute force at scale without treating every user like a suspect.

Rate limiting: do it per IP and per account (or it won’t hold)

Simple IP-based rate limiting is a start, but brute force tooling is happy to rotate IPs. If you only limit by IP, you’ll slow the clumsiest attackers and annoy shared networks.

A stronger setup layers counters:

  1. Per account: e.g. username/email fails per 15 minutes
  2. Per IP and subnet/ASN: useful for bursts from a single network
  3. Per device/session (when you can): helps with distributed attempts

Concrete example: limit POST /login to 10 attempts/min/IP, and 5 failed attempts/15 min/account. The first catches hammering; the second catches “slow and distributed”.

Cloudflare’s own rate limiting best practices show how granular rules (method + path + penalty windows) are commonly applied to login endpoints (Cloudflare rate limiting best practices).

Don’t “lock the account” as your only move

Account lockout feels satisfying, but OWASP notes it has blind spots: it’s ineffective against attacks spread across many usernames, and it can be abused as a denial-of-service against your users (OWASP: Blocking Brute Force Attacks).

Prefer progressive friction over hard lockouts:

  1. First few failures: silent throttling (small backoff)
  2. Continued failures: step-up verification
  3. Clearly automated patterns: block/throttle at the network level
  4. Only lock accounts when you have strong evidence of compromise (and a safe recovery path)

Step-up verification: the sweet spot for real-world login flows

This is where a CAPTCHA alternative or human verification layer pays for itself. You don’t want a permanent gate; you want a smart one.

Trigger step-up when signals stack up, such as:

  1. 3–5 consecutive failures for an account
  2. New device + unusual geo/time-of-day
  3. Data-centre IPs or high-risk ASN
  4. Very low success rate across many accounts (spraying pattern)

Then your response is simple: prove you’re human, then try again.

Make MFA/passkeys the “exit ramp” from repeated challenges

If a user keeps hitting step-up, that’s a hint: either they’re struggling, or someone’s poking the account. Give them a better, safer path.

OWASP’s MFA guidance is blunt: MFA is one of the best defences against password attacks, including brute force and credential stuffing (OWASP MFA Cheat Sheet).

Practical product pattern:

  1. If an account repeatedly triggers step-up: nudge to enable MFA/passkeys
  2. If a login is high risk: require MFA (not “maybe show a puzzle”)

Optional: a ship-this-sprint policy (sane defaults)

Use this to get something live quickly, then tune with data:

  1. Allow: known device/session, normal velocity
  2. Step-up: ≥3 failed attempts in 10 minutes or new device + unusual network
  3. Throttle: exponential backoff after each failure (e.g. 0s → 2s → 5s → 15s)
  4. Block: clear automation fingerprints, or high-rate attacks across many accounts from one network

This prevents brute force attacks from being “cheap”, while keeping happy-path login fast.

What to measure (so you know it’s working)

If you don’t measure it, you’ll either over-challenge humans or under-stop bots.

Track:

  1. Failed logins per account (p95 / p99)
  2. Step-up rate and pass rate
  3. Login success rate (overall + by segment)
  4. Time-to-login (p95)
  5. Confirmed account takeovers/week

Where Humans Only fits

Humans Only is built for bot prevention on high-value endpoints like login and password reset: fast (typically under 2 seconds), privacy-first (zero tracking), and easy to drop in.

Use Humans Only to run risk-based human verification: most users flow through normally, while suspicious login attempts get stepped up or blocked with clear, measurable outcomes.

If you’re ready to prevent brute force attacks without turning authentication into a never-ending UX debate, Humans Only helps you Stop Bots, Welcome Humans.

We use cookies to improve your experience and anonymously analyze usage.