Skip to content
Muhammet Şafak
tr
Asked by: Murat Answered:

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.

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.

  1. 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 username from thousands of IPs blows up on that dimension.
  2. Tighten dynamically when the failure rate spikes. Keep limits loose normally, then automatically narrow them when the error (failed-login) rate jumps. Use a threshold that hardens on the attack signal, not a fixed one.
  3. 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. This separately closes the single-target version of the distributed attack (account takeover).
  4. Push true volumetric DDoS to the edge. Your app can’t absorb an L3/L7 flood — accept that. Leave the volumetric attack to an edge layer like Cloudflare; your Redis limiter stops smart, targeted abuse, but a flood needs the infrastructure layer.
  5. Fail closed on the login path, and don’t leak which dimension tripped. If the limiter or Redis errors, close the login (fail-closed), don’t leave it open. When you reject, don’t tell the attacker which dimension blew up (e.g. “your IP is blocked”); log the decisions, but only for your own tuning.

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.

Tags: #resilience#security#redis
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

More Questions

All questions

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind