How do I build smart rate limiting against distributed brute force and DDoS?
Question
Our API's login endpoint is under heavy brute force and DDoS. Standard IP-based rate limiting (60 requests/min) doesn't help because the attacker uses thousands of different IPs behind proxies. Using a Redis-backed sliding window counter or token bucket, how do I build a dynamic, smart rate limiter that combines IP, username, User-Agent and country code?
Answer
Short answer: a per-IP limit is helpless against rotating proxies — so don’t dimension only on IP. Break the attack with multi-dimensional keying and defense in depth.
Short answer
The real problem is this: because the attacker rotates thousands of IPs, the “60 per IP” rule never trips for any individual IP. You need to catch the common denominator of the attack. I covered the load-side version of the same “reject at the door to protect what’s behind” logic in the graceful degradation answer.
Why
-
A single-dimension counter can’t see a distributed attack. Every IP stays under the threshold while the aggregate crushes the target; the counter has to live on the dimension the attack actually shares.
-
A fixed threshold ignores the attack signal. Running normal-time limits while the failed-login rate spikes is treating an attack as normal traffic.
-
The application layer can’t absorb a volumetric flood. Trying to stop an L3/L7 flood with a Redis limiter is fighting at the wrong layer.
What to do
-
Key the Redis sliding-window on multiple dimensions. Not a single counter, but counters across several dimensions: username (if one account is being sprayed), IP, IP subnet / ASN, User-Agent fingerprint, country code. Even if one IP looks clean, traffic hitting the same
usernamefrom thousands of IPs blows up on that dimension. Token bucket would solve this too — I prefer sliding-window because it’s easier to combine dimensions in one structure. -
Tighten dynamically when the failure rate spikes. Keep limits loose normally, then automatically narrow them when the failed-login rate jumps.
-
Add account lockout and a challenge against credential stuffing. Apply progressive per-account delay/lockout on failed logins; after N attempts require a CAPTCHA or proof-of-work.
-
Push true volumetric DDoS to the edge. Leave the volumetric attack to an edge layer like Cloudflare; your Redis limiter stops smart, targeted abuse.
-
Fail closed on the login path, and don’t leak which dimension tripped. If the limiter or Redis errors, close the login. When you reject, don’t tell the attacker which dimension blew up; log the decisions for your own tuning only.
Bottom line: I’d set up a sliding-window in Redis on account + IP + ASN, add account lockout for credential stuffing, and leave the volumetric part to the edge. A single dimension (IP) is never enough; the combination that catches the common denominator of the attack is what solves it.
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.