Implementing Rate Limiting and Throttling
1. Understanding Brute-Force Attacks
| Type | Detail |
|---|---|
| Password spraying | One password across many accounts |
| Credential stuffing | Leaked credentials from other breaches |
| Enumeration | Probe for valid usernames |
| Mitigation | Rate limit + lockout + MFA + CAPTCHA |
2. Implementing Login Rate Limiting
Example: Express + Redis
import rateLimit from "express-rate-limit";
import RedisStore from "rate-limit-redis";
app.post("/login", rateLimit({
store: new RedisStore({ sendCommand: (...a) => redis.call(...a) }),
windowMs: 15 * 60_000, max: 5,
keyGenerator: (req) => req.body.email + ":" + req.ip,
standardHeaders: true
}), loginHandler);
3. Using IP-Based Rate Limiting
| Aspect | Detail |
|---|---|
| Pro | Catches unauthenticated abuse |
| Con | NAT (corporate, mobile carriers) — false positives |
| CDN | Use True-Client-IP / CF-Connecting-IP; trust only proxy |
4. Implementing User-Based Rate Limiting
| Key | Detail |
|---|---|
| Authenticated | By user ID |
| Anonymous | Fall back to IP / fingerprint |
| Combined | (user + IP) tuple |
5. Using Sliding Window Algorithm
| Algorithm | Detail |
|---|---|
| Fixed window | Bursty at boundary |
| Sliding log | Accurate but memory-heavy |
| Sliding window counter | Approximation — best balance |
| Token bucket | Allows bursts up to capacity |
| Leaky bucket | Smooth output rate |
6. Implementing Token Bucket Algorithm
Example: Redis Lua
-- KEYS[1]=bucket, ARGV: now, rate, capacity, cost
local b = redis.call("HMGET", KEYS[1], "tokens","ts")
local tokens = tonumber(b[1]) or tonumber(ARGV[3])
local ts = tonumber(b[2]) or tonumber(ARGV[1])
tokens = math.min(tonumber(ARGV[3]), tokens + (ARGV[1]-ts)*ARGV[2])
if tokens < tonumber(ARGV[4]) then return 0 end
tokens = tokens - ARGV[4]
redis.call("HMSET", KEYS[1], "tokens", tokens, "ts", ARGV[1])
return 1
7. Using Rate Limit Headers
| Header | Standard |
|---|---|
| RateLimit-Limit | draft-ietf-httpapi-ratelimit-headers |
| RateLimit-Remaining | Same |
| RateLimit-Reset | Seconds to reset |
| Retry-After | RFC 9110 — on 429/503 |
8. Implementing Progressive Delays
| Attempt | Delay |
|---|---|
| 1-3 | 0 |
| 4 | 1s |
| 5 | 2s |
| 6+ | Exponential (2^n) up to cap |
9. Handling Rate Limit with CAPTCHA
| Service | Detail |
|---|---|
| reCAPTCHA v3 | Score-based, invisible |
| hCaptcha | Privacy-focused |
| Cloudflare Turnstile | Privacy-first, no puzzle |
| Apple Private Access Tokens | RFC 9577 — anonymous client attestation |
10. Implementing Distributed Rate Limiting
| Approach | Detail |
|---|---|
| Redis cluster | Single source for counters |
| Sliding window in Redis | ZADD + ZREMRANGEBYSCORE |
| Edge | Cloudflare/Fastly rate limit rules |
| Sidecar | Envoy ratelimit service |