The login endpoint is the one part of your application you publish, document, and invite every user to reach, which makes it the surface an attacker can pound on indefinitely while doing nothing that looks like an attack. It accepts usernames and passwords by design, so credentials reused across services and stolen in someone else’s breach arrive looking exactly like a returning customer.
Credential stuffing has industrialized around one simple fact: based on the credentials alone, a legitimate sign-in and an account takeover are the same request. Just how common is it? A Verizon study found that credential stuffing accounts for a median of 19% of all authentication attempts, rising to 25% for enterprise-sized companies.
Hardening the endpoint against credential stuffing comes down to three moves: raise the cost of each guess, narrow what a correct guess unlocks, and spot the campaign by its shape rather than its payload.
Rate limiting and monitoring only cover the endpoints you have enumerated, and the login form is only a small part of the surface. Inventory the password reset and forgot-username flows, the MFA enrollment and recovery routes, the OAuth token and refresh endpoints, the mobile sign-in route, and any legacy SSO callback still honoring HTTP basic auth.
Attack automation has already mapped these. OpenBullet 2, the most widely used credential stuffing framework, ships community configs, including more than a hundred aimed at specific API login endpoints. Treat every route that accepts a credential or issues a token as in scope, including the JSON API behind your single-page app, where there is often no challenge.
Credential stuffing now runs through residential proxy networks that span millions of home and mobile IPs, so a single campaign fans out across tens of thousands of addresses, each making only a handful of attempts to stay under the per-IP threshold.
Layer the limits: a token-bucket or sliding-window cap per account, a looser cap per IP, and a reputation-weighted cap per autonomous system to catch a clustered proxy pool.
The harder signal is cross-account velocity. Stuffing tools try each credential once against a given account, so a per-account failure counter sees one miss and resets. Track the global failed-login rate and the spread of distinct accounts per source, and hold those counters in a shared store at the edge so a distributed campaign stays visible even as it hops between nodes. Respond with HTTP 429 and a Retry-After header.
NIST's SP 800-63B-4, finalized in July 2025, instructs verifiers to check chosen secrets against known compromised password lists, while discouraging composition rules and routine password rotation.
The reference implementation is the Pwned Passwords API: the client takes the SHA-1 of the candidate, sends the first five hex characters of the digest as a range query, and matches the returned suffixes locally, so the full hash never leaves the client.
Screen passwords at registration, at change, and, where practical, at every login, because combo lists are only half the threat now. Most fresh credentials come from infostealer malware that lifts saved passwords from the browser, so even a unique, high-entropy password can surface in a log within days.
Multi-factor authentication (MFA) stays the highest-value control here, because a correct password alone is no longer enough. Time-based one-time passwords (RFC 6238) raise the bar against plain stuffing, though they stay phishable: adversary-in-the-middle (AitM) kits proxy the real login page and relay the one-time code in real time, and push-fatigue attacks spam approvals until a tired user taps one.
Public-key factors retire the shared secret. A WebAuthn or FIDO2 passkey signs a server challenge with a private key that never leaves the authenticator, and the browser scopes that key to the relying-party ID, so a credential minted for your origin is inert against a look-alike domain. Default new users to MFA, turn on number matching for push factors, and treat passwordless as the destination.
A login endpoint that returns “invalid password” for live accounts and “no such user” for the rest is an enumeration oracle. So is one that answers in 40ms for an unknown username and 200ms for a real one, because only the real account reaches the password-hashing step, a difference a script can measure easily.
Return one generic error for every rejected attempt, hold the HTTP status constant, and equalize timing by running the verification against a fixed dummy hash even for a nonexistent username.
Apply the same discipline to registration, password reset, and forgot-username, where a distinct message or a quicker reply leaks membership just as cleanly.
Blanket CAPTCHA trains real users to solve challenges on reflex and barely slows a solving service, so identify the automation lower in the stack. A modern bot signature combines the TLS ClientHello fingerprint (JA4, the successor to JA3 that sorts cipher suites and so defeats bots that use cipher stunting to dodge JA3), the HTTP/2 settings-and-priority fingerprint, header order and casing, and the protocol advertised in ALPN.
Those are signals a scripted client struggles to reproduce while posing as a browser. Feed them into a behavioral risk-scoring model and challenge only the sessions that read as synthetic. Dedicated bot management correlates a fingerprint across the whole estate, so one JA4 driving login failures across thousands of accounts surfaces as a single actor even when its IPs are scattered across a residential proxy pool.
Locking an account after a fixed number of failures turns the login endpoint into a denial-of-service weapon: feed deliberate bad passwords against a list of known usernames and you lock the legitimate owners out at will. Prefer exponential backoff keyed to the identity, escalating to a step-up challenge, layered on top of the account and ASN rate limits described earlier.
Where you do block, try to scope it to the offending source or device rather than the account, and key it to a server-set device cookie so a returning legitimate browser is recognized. Expose a self-service recovery path too, so a temporary block becomes a thirty-second detour rather than a support ticket.
The password field is rarely the way in. Reset, MFA enrollment, and token refresh each mint or replace a credential while sidestepping the password. Reset tokens should carry at least 128 bits of entropy from a cryptographically secure generator, be stored only as a hash, expire within an hour, invalidate on first use, and re-prompt for the existing MFA factor.
Treat OAuth as an authentication surface in its own right. Rotate refresh tokens on every exchange and watch for replay: a refresh token presented twice means the earlier copy leaked, and the whole token family should be revoked immediately. Scope every token to the narrowest audience and lifetime the flow allows, and bind it to the client where you can.
Authentication is the start of the session, and the session is the asset the attacker is after. Issue a fresh session identifier on every successful login and every privilege change to prevent session fixation, and carry it in a cookie marked Secure, HttpOnly, SameSite=Lax, and the __Host- prefix, which pins it to the exact origin and blocks a subdomain from overwriting it.
Keep lifetimes short with sliding renewal rather than a token that lives for weeks, and bind sensitive operations, such as changing a password or adding a payout destination, to a fresh re-authentication. Where the stakes justify it, bind the token to the client with proof-of-possession (DPoP) or mutual TLS, so a stolen cookie replays nowhere on its own.
A credential stuffing campaign has a signature in aggregate that no single request reveals: a failed-login rate climbing across many distinct accounts, a sudden fan-out of source ASNs, a rising share of submitted passwords that match the breach corpus, a cluster of identical JA4 fingerprints, and MFA prompts generated faster than anyone approves them. Each of these only becomes visible when you aggregate across requests.
Log every authentication event with outcome, source IP and ASN, client fingerprint, and result code, and alert on those rates rather than any single attempt. Identity providers catch these campaigns through dedicated log events for failed cross-origin authentication and leaked-password sign-ins. Stream the same signals to the edge so detection and mitigation share a control point and you throttle the campaign while it runs.
Each of these ten controls covers a different stage of an attack. Breached-password screening removes the easy guesses, MFA catches the ones that still get through, rate limiting and bot detection slow the automation to a crawl, and logging tells you when an attack is underway. Together they leave far fewer gaps than any single layer.
They also share a starting assumption. The teams that come through a credential stuffing wave intact treat every password their users have ever chosen as already leaked, sitting in a combo list or an infostealer log. Once you design for that, the goal is easier: the login flow has to stay safe even when the attacker knows the correct password.
Qrator Labs sits in front of your authentication endpoints and handles the edge rate limiting, WAF, and bot management, soaking up the automated traffic before it reaches your application. The rest comes down to the practices outlined above.
Share your experience and expectations regarding DDoS protection. Your answers will help us tailor solutions to meet your cybersecurity needs.
Tell us about your company’s infrastructure and critical systems. This will help us understand the scope of protection you require.
Help us learn about how decisions are made in your company. This information will guide us in offering the most relevant solutions.
Let us know what drives your choices when it comes to DDoS protection. Your input will help us focus on what matters most to you.