Rate Limiting & Abuse Prevention
Protect APIs from abuse with token bucket rate limiting, sliding windows, distributed counters in Redis, and progressive penalties.
Rate limiting protects services from intentional abuse, accidental overload, and denial-of-service attacks. Effective rate limiting matches algorithm to threat, chooses meaningful keys, and communicates limits clearly to API consumers.
Rate limit at multiple layers: network edge (WAF/CDN), API gateway, and application. Use Redis for distributed state. Return clear 429 responses with Retry-After headers. Progressive penalties for repeat violators.
Workflow
- Choose the right algorithm for your use caseWrong algorithm either allows burst abuse or penalizes legitimate traffic.
- Define meaningful rate limit keysIP-only limits fail for NAT'd networks; user-only limits miss unauthenticated abuse.
- Implement with Redis for distributed stateSingle-node counters fail in multi-instance deployments.
- Return clear limit responsesClients need limit info to implement proper backoff without hammering the server.
- Add progressive penalties for abusersStatic limits can still be gamed; progressive penalties deter persistent abuse.
Output Format
Rate limits at edge + application layer, Redis sliding window counters, layered key strategy, 429 responses with Retry-After, progressive penalty system.
Examples
Express rate limit: `import rateLimit from "express-rate-limit"; import RedisStore from "rate-limit-redis"; app.use(rateLimit({ windowMs: 60000, max: 100, store: new RedisStore({ client: redis }) }))`Custom sliding window Lua: `local key=KEYS[1]; local now=ARGV[1]; local window=ARGV[2]; redis.call("ZADD",key,now,now); redis.call("ZREMRANGEBYSCORE",key,0,now-window); return redis.call("ZCARD",key)`Response headers: `res.set({ "X-RateLimit-Limit": 100, "X-RateLimit-Remaining": Math.max(0, 100-count), "Retry-After": Math.ceil((windowEnd-Date.now())/1000) })`Edge Cases & Gotchas
- IPv6 requires subnet-level limiting (/48 or /64 blocks), not individual addresses
- Distributed rate limiting has ~1ms Redis latency-bypass for health check endpoints
- API keys can be shared: combine with user account limits to prevent key sharing abuse
When to Break These Rules
- Internal service-to-service calls within the same trust boundary don't need rate limiting-use circuit breakers instead for backpressure.
Reference Files
Stripe rate limiting blog: https://stripe.com/blog/rate-limitersCloudflare rate limiting: https://developers.cloudflare.com/waf/rate-limiting-rules/Redis rate limiting patterns: https://redis.io/glossary/rate-limiting/