cyber-security claude-curated

Rate limiting caps how often a particular actor can perform a particular action within a window. It is one of the cheapest, broadest defensive controls, sitting at the intersection of Cyber Security, reliability, and cost management.

Why rate limit

  • DDoS mitigation — absorb or shed volumetric and application-layer floods (also see DoS) before they exhaust origin capacity.
  • brute-force protection — slow down credential stuffing, password spraying, OTP guessing, token enumeration. Pair with MFA.
  • API abuse — prevent scraping, mass enumeration of resources, cost-shifting attacks against metered backends.
  • Cost control — protect downstream services that are billed per-request (LLM APIs, third-party SaaS, paid data feeds).
  • Fairness — prevent one tenant or one buggy client from starving others of capacity.

Layers where rate limiting can apply

Each layer adds protection but also operational complexity. Defence in depth typically involves several.

  • Edge / CDN (Cloudflare, Fastly, Akamai): cheapest place to drop traffic — abuse never reaches the origin. Operates on IP, ASN, country, JA3/JA4 TLS fingerprint, header signatures.
  • WAF (Cloudflare WAF, AWS WAF, Imperva): rate limiting as a rule action, often combined with bot-detection signals. More expressive than raw CDN rules.
  • API gateway (Kong, Apigee, AWS API Gateway): per-route, per-API-key, per-plan quotas. Natural place for tiered service plans.
  • Application (in-process middleware: NGINX limit_req, Express middleware, Rails Rack::Attack, ASP.NET rate limiter): finest-grained, can incorporate authenticated user identity, business-logic context, and per-endpoint policies.

The earlier the layer, the cheaper the rejection but the less context available. Application-layer limits know the user; edge limits only know the IP.

Algorithms

  • Fixed window — count requests in calendar windows (e.g. each minute). Simple, but a client can burst at the window boundary and get 2× the intended budget.
  • Sliding window — count over a moving time interval. More accurate, slightly more state per actor. Common implementation: weighted-sum approximation across two adjacent fixed windows.
  • Token bucket — actor has a bucket of tokens; each request consumes one; tokens refill at a steady rate up to a cap. Smooth burst handling. Common in API quotas (e.g. AWS Lambda throttles, GitHub).
  • Leaky bucket — requests enter a queue that drains at a fixed rate. Enforces a steady output rate; excess is dropped or shed. Good for protecting downstreams that cannot tolerate bursts.

Combining short-term and long-term limits

A single threshold rarely captures intent. Realistic policies stack limits at multiple time horizons:

  • Per-second: 10 req/sec — protects against bursts and probes.
  • Per-minute: 200 req/min — catches sustained abuse below the burst threshold.
  • Per-hour or per-day: 10,000 req/day — caps total budget and shapes scraping cost.

A request must satisfy all active limits.

Identifying the actor

The unit you key off determines the strength of the limit. Choices, from cheapest to most accurate:

  • IP address — free, but defeated by NAT, mobile carrier-grade NAT (CGNAT), VPNs, and shared cloud egress IPs. Risks blocking many real users behind one egress.
  • ASN / network range — group IPs by network owner. Useful for blocking abusive hosting providers without affecting residential users.
  • TLS fingerprint (JA3 / JA4) — distinguishes clients by the shape of their TLS handshake. Helps separate scripted tools from browsers, even on a shared IP.
  • API key — strong identity for B2B APIs; useless if attackers obtain valid keys. Store in Secrets Manager.
  • Authenticated user ID — strongest for logged-in flows; cannot be applied to anonymous endpoints (login, signup). Pairs with OAuth / OIDC tokens.
  • Session / cookie — useful for unauthenticated browser flows, but can be rotated by attackers.

For login endpoints, layer at least two: IP and username, so neither single bypass route works.

Response semantics

The HTTP standard response is 429 Too Many Requests with a Retry-After header indicating either seconds or a date. Well-behaved clients honour this; abusive clients do not, but legitimate SDKs and CLIs benefit.

Adjacent headers communicate quota state:

  • X-RateLimit-Limit
  • X-RateLimit-Remaining
  • X-RateLimit-Reset
  • The standardised RateLimit and RateLimit-Policy headers (RFC 9331 draft).

For login flows, deliberately do not leak whether a 429 was triggered by username or IP — attackers can use that signal for enumeration.

Common pitfalls

  • Shared NAT collateral damage — a school, office, or country can sit behind one egress IP. Per-IP limits bite real users.
  • Health check exemption — internal probes hit endpoints far more often than humans; either exempt them or use unauthenticated cheap endpoints.
  • State loss on restart — in-process counters reset when the process restarts. For meaningful enforcement, store counters in Redis, Memcached, or a similar shared store.
  • Clock skew across nodes — sliding-window implementations drift if nodes disagree on time. Use a centralised store or NTP-synchronised clocks.
  • Backoff loops — clients that retry immediately on 429 amplify the problem. Document Retry-After and exponential backoff.
  • Blocking is loud — hard 429s tell attackers their probe was detected. Some teams prefer shadow throttling (silently slowing or returning fake-success responses) for credential stuffing, to avoid signalling.
  • Distinguishing humans from automation — a hard rate limit can be paired with CAPTCHA challenges as a softer interstitial.

Rate limiting vs other controls

Rate limiting alone does not stop a determined attacker — it raises cost and slows them. Combine with:

  • Bot management (signal-based detection, CAPTCHA challenges).
  • Anomaly detection on behavioural patterns — feeds into SIEM / SOAR and IDS / IPS signals.
  • Account lockout policies for repeated auth failure.
  • WAF rules for known abuse signatures — see Monitoring Cloudflare Security Events and OWASP CRS.

Key takeaways

  • Apply at multiple layers; the earliest layer that has enough context wins on cost.
  • Combine short-term and long-term limits.
  • Choose actor identifiers carefully — IP alone is weak in a NAT-heavy world.
  • Always return 429 with Retry-After; never leak which dimension tripped on auth endpoints.
  • Persist counter state outside the process.

See also

References

  • RFC 6585 — Additional HTTP Status Codes (429)
  • IETF draft: RateLimit header fields for HTTP
  • OWASP API Security Top 10 — API4: Unrestricted Resource Consumption
  • Cloudflare Learning Center: rate limiting