Rate Limiting
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7) — owasp-zap and semgrep can flag missing rate limit middleware patterns but this is largely a security review concern; absence of rate limiting is invisible to typical CI.
Closest to 'touches multiple files / significant refactor in one component' (e5) — quick_fix says implement token bucket/sliding window with Redis across login, registration, password reset, and API endpoints. Not a one-liner; requires middleware setup, storage backend, and applying to many routes.
Closest to 'persistent productivity tax' (b5) — applies across all web/api contexts; every new endpoint must consider rate limit policy, key strategy (user+IP+API key), and headers. Ongoing tax but not architecture-defining.
Closest to 'serious trap' (t7) — misconception states IP-only rate limiting feels obviously correct but is defeated by NAT, proxies, and botnets; the intuitive implementation is materially wrong and gives false sense of security.
Also Known As
TL;DR
Explanation
Rate limiting enforces request quotas per user, IP, or API key. Algorithms include: Fixed Window (simple counter per time window — vulnerable to burst at window boundary), Sliding Window (smoothed count over a rolling period), Token Bucket (tokens refill at a rate; bursts allowed up to bucket size), and Leaky Bucket (requests drain at a fixed rate, excess queued or dropped). In PHP, implement with Redis using atomic Lua scripts or the INCR/EXPIRE pattern. Return 429 Too Many Requests with a Retry-After header. Apply at multiple layers: Nginx/Caddy at the network edge, application middleware for per-user limits.
Common Misconception
Why It Matters
Common Mistakes
- Rate limiting per IP only — attackers use distributed botnets with thousands of different IPs.
- Applying rate limits only to authentication routes and ignoring expensive API endpoints.
- Returning 200 OK with a fake success response instead of 429 — attackers cannot detect the limit.
- Not including Retry-After headers — legitimate clients cannot back off gracefully.
Avoid When
- Internal service-to-service calls on a trusted network — rate limiting adds latency and complexity with no security benefit.
- The rate limit is set so high it never triggers — a limit that is never hit protects nothing.
- Applied without clear error responses — clients must receive a 429 with Retry-After so they can back off correctly.
- Using IP-based limiting alone for authenticated APIs — one IP may serve many legitimate users behind a NAT.
When To Use
- Any public-facing API endpoint to prevent abuse, scraping, and denial-of-service.
- Authentication endpoints — rate limiting login and password-reset prevents brute force attacks.
- Expensive operations (email sending, PDF generation, ML inference) that must be protected from runaway consumers.
- Per-user or per-API-key limits to enforce fair usage in multi-tenant SaaS products.
Code Examples
// No rate limiting — login endpoint accepts unlimited attempts
$key = 'login_attempts:' . $ip;
$attempts = $redis->incr($key);
if ($attempts === 1) $redis->expire($key, 300);
if ($attempts > 5) { http_response_code(429); exit; }