OWASP & AppSec

Rate limiting : pourquoi et comment en 2026

Rate limiting 2026 : pourquoi (DoS, brute force, scraping, abus), algorithmes (token bucket, sliding window), patterns API gateway, code Redis, NGINX, Cloudflare.

Naim Aouaichia
18 min de lecture
  • Rate Limiting
  • Throttling
  • Anti-DoS
  • API Security
  • Redis
  • Nginx
  • Cloudflare
  • OWASP API4

Le rate limiting est la technique défensive qui limite le nombre de requêtes qu'un client (humain, machine, IP) peut envoyer à un service dans une fenêtre temporelle donnée. Codifié par OWASP API Security Top 10 2023 sous l'identifiant API4:2023 (Unrestricted Resource Consumption), c'est l'une des défenses les plus fondamentales et les plus fréquemment mal implémentées en 2026. Sans rate limiting effectif, une API ou un service web devient vulnérable à cinq classes d'abus distinctes : déni de service volumique (DoS), brute force d'authentification (credential stuffing), scraping et énumération massive de données (BOLA enumeration, scraping de contenu), abus de business logic (achats massifs, ticket scalping), et déni de service algorithmique (zip bomb, regex catastrophic backtracking, GraphQL queries imbriquées). Implémenter un rate limiting robuste implique cinq couches cumulatives (CDN edge, reverse proxy, API gateway, application Redis, business logic), le choix d'un algorithme adapté (Token bucket dominant en 2026, Sliding window counter pour précision), et l'usage des headers HTTP standardisés par RFC 9651 (mai 2024). Cet article détaille les 5 classes d'abus défendues, les 5 algorithmes principaux comparés, les patterns d'implémentation par couche avec code Redis, NGINX et Cloudflare, les headers HTTP standards, les techniques de bypass et leurs défenses, le rate limiting distribué multi-instance, le tuning et le monitoring opérationnel.

Pourquoi le rate limiting : 5 classes d'abus défendues

Sans rate limiting, cinq familles d'attaques ou abus deviennent triviales.

1. Déni de service volumique (DoS)

Un attaquant envoie un volume massif de requêtes pour saturer le serveur (CPU, mémoire, connexions, base de données). Sans rate limit, un script Python basique peut générer 10 000+ requêtes/seconde depuis une seule machine, suffisant pour mettre à genou la plupart des APIs non protégées.

Le DDoS volumique avec attaquant distribué (botnet) ne se résout pas par rate limiting per-IP seul, mais le rate limiting reste la première couche de défense applicative.

2. Brute force d'authentification

Tester systématiquement des combinaisons login/password ou des codes OTP/SMS jusqu'à trouver la bonne. Sans rate limit sur l'endpoint d'authentification, un attaquant peut tester :

  • 10 000 mots de passe par seconde sur un endpoint /api/auth/login.
  • 1 million de codes OTP 6 chiffres en quelques minutes (1M combinaisons possibles).
  • Credential stuffing avec liste de credentials volés (par exemple Have I Been Pwned 12 milliards d'entrées 2026).

Documenté dans OWASP API Security Top 10 API4:2023 et OWASP API2:2023 (Broken Authentication).

3. Scraping et énumération massive

Extraction de données massives via API publique :

  • Énumération BOLA : tester séquentiellement /api/orders/1, 2, 3, ... pour exfiltrer toutes les commandes (variant de l'incident T-Mobile janvier 2023, 37M comptes).
  • Scraping de catalogues : extraction de tous les produits, prix, avis pour un concurrent.
  • Énumération de comptes : tester /api/users/check?email=... pour identifier les comptes existants.

Sans rate limit sémantique, l'attaquant exfiltre une base entière en quelques heures.

4. Abus de business logic

Patterns spécifiques à la logique métier :

  • Ticket scalping : achat massif automatisé de tickets pour revente.
  • Promo code abuse : test de tous les codes promo possibles ou utilisation massive d'un code unique.
  • Account creation spam : création de milliers de faux comptes pour spam ou manipulation.
  • Multi-redemption : utilisation répétée d'un coupon à usage unique avant invalidation backend.

OWASP API6:2023 (Unrestricted Access to Sensitive Business Flows) est la classe formalisée pour cette catégorie.

5. Déni de service algorithmique

Requêtes peu nombreuses mais coûteuses qui saturent le serveur :

  • Zip bomb : archive 42KB qui explose en 4,5 PB à la décompression.
  • Regex catastrophic backtracking (ReDoS) : input crafted qui fait timeout une regex côté serveur.
  • GraphQL queries imbriquées profondes : query qui demande tout le graphe en cascade.
  • GraphQL aliases batch : 1000 mutations dans une seule requête HTTP.
  • Compression bombs : payload compressé qui explose en mémoire.

Le rate limiting volumique standard ne couvre pas ces cas. Compléter avec limites sémantiques (max depth GraphQL, max body size, max regex execution time).

Les 5 algorithmes de rate limiting

Comparaison des algorithmes principaux. Choix selon précision requise, tolérance bursts, coût d'implémentation.

1. Fixed Window Counter

Le plus simple. Compteur incrémenté pour chaque requête, reset toutes les N secondes.

Window 0-60s:  [count=0 → 100, OK | count=101+, 429]
Window 60-120s: [count=0 → 100, OK | count=101+, 429]

Avantages : simple, peu coûteux. Inconvénient : effet de bord aux frontières (un client peut faire 100 req à 0:59 puis 100 req à 1:00 = 200 req en 1 seconde réelle).

Convient pour : APIs simples, prototypes, contextes où la précision n'est pas critique.

2. Sliding Window Log

Stockage du timestamp de chaque requête. Pour valider : compter les timestamps dans la fenêtre [maintenant - N, maintenant].

Avantages : précision parfaite, pas d'effet de bord. Inconvénient : coût mémoire élevé (stocker chaque timestamp).

Convient pour : APIs faible volume avec exigence de précision absolue.

3. Sliding Window Counter

Compromis entre Fixed Window et Sliding Window Log. Combine les compteurs de la fenêtre courante et précédente avec pondération linéaire.

Fenêtre précédente (0-60s) : 80 requêtes
Fenêtre courante (60-120s) : 30 requêtes, on est à 90s (50 % dans la fenêtre)
 
Estimation pondérée : 80 × (1 - 0.5) + 30 = 70 requêtes effectives
Si limite = 100, OK

Avantages : précision proche du sliding log, coût mémoire constant. Inconvénient : approximation (acceptable en pratique).

Convient pour : majorité des APIs production. Algorithme dominant en 2026 pour les solutions modernes.

4. Token Bucket

Le bucket se remplit à débit constant (par exemple 10 tokens/seconde). Chaque requête consomme un token. Si bucket vide, requête refusée.

Bucket capacity: 100 tokens (burst max)
Refill rate: 10 tokens/second
 
Burst possible : 100 requêtes en 1 seconde puis attendre.
Régime stable : 10 requêtes/seconde sustained.

Avantages : permet bursts courts tolérés, comportement intuitif pour développeurs, implémentation simple Redis. Inconvénient : moins prévisible que sliding window pour limites strictes.

Convient pour : APIs publiques (utilisateurs apprécient la tolérance burst), pattern dominant 2026 pour la majorité des cas.

5. Leaky Bucket

Variante du token bucket. Les requêtes entrantes remplissent le bucket, les requêtes sortent à débit constant. Si bucket plein, requêtes refusées.

Avantages : lisse les bursts, garantit débit constant côté serveur. Inconvénient : peut imposer latence aux requêtes valides en cas de burst.

Convient pour : protection downstream (par exemple : API qui consomme une API tierce avec rate limit strict, lisse les requêtes vers le tiers).

Comparaison synthétique

AlgorithmePrécisionCoût mémoireTolérance burstCas d'usage type
Fixed WindowMoyenne (effet de bord)Très faiblePossible aux frontièresPrototypes, APIs simples
Sliding Window LogParfaiteTrès élevéAucuneAPIs très sensibles, faible volume
Sliding Window CounterTrès bonneFaibleLimitéeProduction moderne, APIs critiques
Token BucketBonneFaibleConfigurableAPI publique standard, dominant 2026
Leaky BucketBonneFaibleLisseProtection downstream API tierces

Couche 1 — Edge / CDN (Cloudflare, AWS WAF, Akamai)

Premier filet de défense. Rate limiting au plus proche du client, avant même d'atteindre l'infrastructure.

Cloudflare Rate Limiting

# Configuration via Cloudflare Dashboard ou API
Rule: Login Brute Force Protection
- If: URI Path equals "/api/auth/login"
- Method: POST
- Threshold: 10 requests per 1 minute per IP
- Action: Block for 1 hour
- Response code: 429

Cloudflare offre rate limiting basique gratuit, plus avancé en plans Business ($200/mois) et Enterprise.

AWS WAF Rate-based rules

{
  "Name": "RateLimitPerIP",
  "Priority": 1,
  "Statement": {
    "RateBasedStatement": {
      "Limit": 2000,
      "AggregateKeyType": "IP"
    }
  },
  "Action": { "Block": {} },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "RateLimitPerIP"
  }
}

Limit minimum 100 requêtes par IP sur fenêtre 5 minutes.

Avantages couche edge

  • Absorbe les attaques volumiques sans charger l'origine.
  • Protection avant que la requête n'atteigne le réseau interne.
  • Géo-distribuée naturellement.

Limites

  • Granularité limitée (souvent uniquement par IP).
  • Pas de connaissance du contexte applicatif (ne peut pas rate limit par user ID).
  • Cas d'usage simples uniquement.

Couche 2 — Reverse proxy (Nginx, HAProxy)

Couche application-aware sans modifier le backend.

Nginx avec limit_req_zone

http {
    # Définition de la zone : 10 MB pour stocker les compteurs IP
    limit_req_zone $binary_remote_addr zone=api_general:10m rate=100r/s;
    limit_req_zone $binary_remote_addr zone=auth_strict:10m rate=5r/m;
    
    # Limit par utilisateur authentifié (si JWT décodé via auth_request)
    limit_req_zone $http_x_user_id zone=user_quota:10m rate=1000r/m;
    
    # Limite de connexions simultanées
    limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
    
    server {
        listen 443 ssl;
        
        # Toutes les routes : 100 req/sec par IP avec burst 200
        location / {
            limit_req zone=api_general burst=200 nodelay;
            limit_conn conn_per_ip 50;
            proxy_pass http://backend;
        }
        
        # Login : très restrictif
        location /api/auth/login {
            limit_req zone=auth_strict burst=2;
            proxy_pass http://backend;
        }
        
        # Endpoints authentifiés : limite par utilisateur
        location /api/v1/ {
            limit_req zone=user_quota burst=100;
            proxy_pass http://backend;
        }
    }
}

Headers retour Nginx

# Custom error page pour 429 avec header Retry-After
error_page 429 /429.json;
location = /429.json {
    default_type application/json;
    add_header Retry-After 60 always;
    return 429 '{"error": "rate_limited", "retry_after": 60}';
}

HAProxy équivalent

frontend api_front
    bind *:443 ssl crt /etc/ssl/cert.pem
    
    # Tracking par IP
    stick-table type ip size 100k expire 30s store http_req_rate(10s)
    http-request track-sc0 src
    
    # Refus si > 100 req/10sec par IP
    http-request deny if { sc_http_req_rate(0) gt 100 }
    
    default_backend api_back

Couche 3 — API Gateway (Kong, Apigee, AWS API Gateway)

Couche dédiée API avec rate limiting riche en fonctionnalités.

Kong Rate Limiting plugin

# Plugin Kong déclaratif
plugins:
- name: rate-limiting
  config:
    second: 5
    minute: 100
    hour: 1000
    day: 10000
    policy: redis
    redis_host: redis.internal
    redis_port: 6379
    fault_tolerant: true
    hide_client_headers: false
    limit_by: consumer    # ou ip, credential, header

Headers automatiquement ajoutés :

HTTP/1.1 200 OK
RateLimit-Limit: 100
RateLimit-Remaining: 42
RateLimit-Reset: 35
X-RateLimit-Limit-Minute: 100
X-RateLimit-Remaining-Minute: 42

AWS API Gateway Usage Plans

Quota globaux + per-key, configurés par Usage Plan associé à API key.

# CloudFormation snippet
UsagePlan:
  Type: AWS::ApiGateway::UsagePlan
  Properties:
    UsagePlanName: standard
    Throttle:
      RateLimit: 100        # requêtes/sec moyennes
      BurstLimit: 200       # burst max
    Quota:
      Limit: 1000000        # requêtes par période
      Period: MONTH

Comparaison gateways 2026

GatewayPlugin rate limitBackend stockageParticularité
Kongrate-limiting (officiel)Redis, local, clusterRiche, déclaratif YAML
ApigeeQuota policyApigee distributedEnterprise mature
AWS API GatewayUsage PlansAWS-managedNative AWS, simple
Azure API ManagementRate limit policiesAzure-managedNative Azure, XML policies
TykRate limit middlewareRedisOSS + Enterprise, GraphQL natif
KrakenDRate limit middlewareLocal in-memoryTrès performant
TraefikPlugin rate-limitRedisK8s-native

Couche 4 — Application avec Redis

Pour rate limiting ultra-précis et personnalisable au-delà des gateways.

Token Bucket atomic via Redis Lua script

Le pattern recommandé en 2026 : script Lua atomique exécuté côté Redis pour éviter les race conditions.

-- token_bucket.lua
-- KEYS[1] = clé du bucket (par exemple : "rate:user:123")
-- ARGV[1] = capacité max (max tokens)
-- ARGV[2] = refill rate (tokens par seconde)
-- ARGV[3] = timestamp courant (UNIX seconds)
-- ARGV[4] = tokens à consommer (généralement 1)
 
local capacity = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local consume = tonumber(ARGV[4])
 
-- Récupération état précédent
local bucket = redis.call("HMGET", KEYS[1], "tokens", "last_refill")
local tokens = tonumber(bucket[1]) or capacity
local last_refill = tonumber(bucket[2]) or now
 
-- Calcul des tokens accumulés depuis dernier refill
local elapsed = now - last_refill
local refilled = math.min(capacity, tokens + elapsed * rate)
 
-- Tentative de consommation
if refilled >= consume then
    refilled = refilled - consume
    redis.call("HMSET", KEYS[1], "tokens", refilled, "last_refill", now)
    redis.call("EXPIRE", KEYS[1], 3600)  -- TTL pour cleanup
    return {1, refilled}    -- 1 = autorisé, refilled = tokens restants
else
    redis.call("HMSET", KEYS[1], "tokens", refilled, "last_refill", now)
    redis.call("EXPIRE", KEYS[1], 3600)
    return {0, refilled}    -- 0 = refusé
end

Usage côté Python :

import redis
import time
 
r = redis.Redis(host="redis.internal", decode_responses=True)
 
# Charger le script une fois (Redis cache le SHA)
TOKEN_BUCKET_SCRIPT = open("token_bucket.lua").read()
script_sha = r.script_load(TOKEN_BUCKET_SCRIPT)
 
def check_rate_limit(user_id: str, capacity: int = 100, rate: float = 10.0) -> tuple[bool, int]:
    key = f"rate:user:{user_id}"
    now = int(time.time())
    result = r.evalsha(script_sha, 1, key, capacity, rate, now, 1)
    allowed = bool(result[0])
    remaining = int(result[1])
    return allowed, remaining
 
# Usage dans handler API
def api_handler(user_id: str):
    allowed, remaining = check_rate_limit(user_id)
    if not allowed:
        raise HTTPException(
            status_code=429,
            detail="Rate limited",
            headers={
                "Retry-After": "10",
                "RateLimit-Remaining": str(remaining),
            }
        )
    # ... traiter la requête

Sliding Window Counter via Redis Sorted Set

import redis
import time
 
r = redis.Redis(host="redis.internal")
 
def check_sliding_window(key: str, limit: int, window_seconds: int) -> bool:
    now = time.time() * 1000  # millisecondes
    cutoff = now - window_seconds * 1000
    
    pipe = r.pipeline()
    # Supprimer entrées hors fenêtre
    pipe.zremrangebyscore(key, 0, cutoff)
    # Compter requêtes restantes dans fenêtre
    pipe.zcard(key)
    # Ajouter requête courante
    pipe.zadd(key, {str(now): now})
    # TTL pour cleanup
    pipe.expire(key, window_seconds)
    results = pipe.execute()
    
    count = results[1]
    return count < limit
 
# Usage : 100 requêtes par minute
allowed = check_sliding_window("rate:user:123", limit=100, window_seconds=60)

Couche 5 — Business logic (compteurs sémantiques)

Au-delà du rate limiting volumique, les compteurs business spécifiques.

# Exemples de compteurs business en addition du rate limiting volumique
 
# Maximum 10 transactions de paiement par jour par compte
def can_make_payment(user_id: str) -> bool:
    today = datetime.now().strftime("%Y-%m-%d")
    key = f"payments:{user_id}:{today}"
    count = r.incr(key)
    if count == 1:
        r.expire(key, 86400)  # TTL 24h
    return count <= 10
 
# Maximum 3 SMS OTP par heure par numéro
def can_send_otp(phone: str) -> bool:
    hour = datetime.now().strftime("%Y-%m-%d-%H")
    key = f"otp:{phone}:{hour}"
    count = r.incr(key)
    if count == 1:
        r.expire(key, 3600)
    return count <= 3
 
# Maximum 5 reset password par jour par compte
def can_reset_password(email: str) -> bool:
    today = datetime.now().strftime("%Y-%m-%d")
    key = f"reset:{email}:{today}"
    count = r.incr(key)
    if count == 1:
        r.expire(key, 86400)
    return count <= 5

Ces compteurs business sont indépendants du rate limiting volumique et défendent contre les abus de business logic (OWASP API6:2023).

Headers HTTP standards (RFC 9651)

Standardisé en mai 2024 par RFC 9651 RateLimit Header Fields for HTTP. Cinq headers définis.

Headers de réponse

HeaderSignificationExemple
RateLimit-LimitLimite totale dans la fenêtreRateLimit-Limit: 100
RateLimit-RemainingRequêtes restantesRateLimit-Remaining: 42
RateLimit-ResetSecondes avant resetRateLimit-Reset: 35
RateLimit-PolicyDescription de la politiqueRateLimit-Policy: 100;w=60 (100 req par 60s)
Retry-AfterDélai avant retry possible (sur 429)Retry-After: 60 ou date HTTP

Pattern complet

# Réponse normale avec headers indicatifs
HTTP/1.1 200 OK
Content-Type: application/json
RateLimit-Limit: 100
RateLimit-Remaining: 42
RateLimit-Reset: 35
RateLimit-Policy: 100;w=60
 
# Réponse 429 avec Retry-After
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 35
Retry-After: 35
 
{
  "error": "rate_limited",
  "message": "Trop de requêtes. Réessayez dans 35 secondes.",
  "retry_after": 35
}

Headers legacy X-RateLimit-*

Beaucoup d'APIs utilisent encore les headers legacy non standardisés (popularisés par GitHub, Twitter avant la RFC 9651) :

  • X-RateLimit-Limit
  • X-RateLimit-Remaining
  • X-RateLimit-Reset (parfois timestamp UNIX, parfois secondes restantes selon API)

Compatibilité descendante recommandée : émettre les deux variantes pour transition douce.

Patterns de bypass et défenses

Cinq techniques de bypass courantes et leurs contre-mesures.

Bypass 1 — IP rotation via proxies résidentiels

Attaquant utilise des proxies résidentiels (Bright Data, Oxylabs) pour distribuer ses requêtes sur des milliers d'IPs résidentielles.

Défense : compléter rate limit per IP avec rate limit per token utilisateur (l'attaquant doit créer un compte ou voler un token, plus coûteux). Détection comportementale (CAPTCHA, fingerprinting).

Bypass 2 — Header IP spoofing

Attaquant modifie X-Forwarded-For, X-Real-IP, X-Client-IP pour faire croire à des IPs différentes.

Défense : configurer le reverse proxy pour utiliser uniquement l'IP réelle de la connexion TCP, pas les headers HTTP arbitraires (sauf si une infrastructure CDN/LB en frontage de confiance les fournit).

# Nginx : utiliser real IP via header X-Forwarded-For
# UNIQUEMENT si trusted proxy en frontage
set_real_ip_from 10.0.0.0/8;        # Cloudflare, internal LB
real_ip_header X-Forwarded-For;
real_ip_recursive on;
 
# Sinon, utiliser $remote_addr (IP TCP) directement

Bypass 3 — Race conditions

Plusieurs requêtes simultanées qui passent toutes le check de rate limit avant que le compteur soit incrémenté.

Défense : opérations atomiques côté Redis (script Lua, INCR + EXPIRE atomique).

Bypass 4 — Variations d'URL

Attaquant exploite les variations d'URL non normalisées : /api/login, /api//login, /api/login/, /api/LOGIN traités séparément par le rate limiter.

Défense : normalisation de l'URL avant de calculer la clé de rate limit (lowercase, trailing slash uniforme, double slashes éliminés).

Bypass 5 — Endpoints avec pagination

Attaquant fait /api/users?page=1&size=10000 pour exfiltrer 10 000 records en une seule requête, contournant le rate limit per-request.

Défense : limite max sur paramètres de pagination (par exemple size max = 100), rate limiting basé sur les bytes ou records retournés (plus complexe mais possible).

Rate limiting distribué multi-instance

Pour APIs déployées sur plusieurs instances, le rate limiting local par instance est insuffisant (les compteurs ne sont pas partagés).

Pattern Redis centralisé

Tous les instances API consultent le même Redis pour vérifier les compteurs. Performance acceptable jusqu'à plusieurs milliers de req/s grâce à Lua scripts atomiques.

Pattern Envoy ratelimit service

Pour très grande échelle (millions req/s), Envoy ratelimit service (gRPC) avec backend Redis ou autre. Architecture standard chez Lyft (origine Envoy), Stripe, GitHub.

Approximate counters distribués

Pour échelle extrême avec tolérance à l'imprécision : algorithmes type HyperLogLog ou Counting Bloom Filters distribués. Sacrifient précision au profit de la performance.

Monitoring et tuning

Trois métriques essentielles à instrumenter.

Métriques opérationnelles

# Métriques Prometheus typiques
rate_limit_blocked_total{key_type="ip", endpoint="/api/auth/login"}
rate_limit_allowed_total{key_type="user", endpoint="/api/orders"}
rate_limit_threshold_remaining{key="user:123", endpoint="/api/orders"}
 
# Alerting :
# - Volume rate_limit_blocked anormalement élevé sur un endpoint = attaque ou seuil mal tuné
# - Aucun rate_limit_blocked depuis X jours = peut-être seuils trop laxistes

Tuning des seuils

Démarrer en mode "observe" (logging uniquement, pas de blocage) pendant 2 à 4 semaines. Analyser :

  • Distribution des requêtes par utilisateur (P50, P95, P99 par minute).
  • Identifier les utilisateurs heavy hitters légitimes.
  • Fixer le seuil de blocage à environ P99 + 50 % pour ne pas bloquer les utilisateurs légitimes intensifs.

Whitelist documentée

Maintenir une liste des partenaires premium et systèmes internes avec quotas augmentés. Centraliser dans la configuration (par exemple : YAML déclaratif) pour traçabilité.

# Exemple config rate limit avec exceptions
rate_limits:
  default:
    per_ip: 100  # req/sec
    per_user: 1000  # req/min
  exceptions:
    partners:
      - id: partner_premium_a
        per_user: 10000
        contact: contact-a@example.test
        contract_ref: SLA-2026-001
      - id: monitoring_internal
        per_user: 100000
        contact: ops@example.test
        purpose: "Datadog, New Relic synthetic checks"

Points clés à retenir

  • Le rate limiting défend contre 5 classes d'abus distinctes : DoS volumique, brute force d'authentification, scraping et énumération massive (BOLA), abus de business logic, déni de service algorithmique. OWASP API4:2023 le classe parmi les top vulnérabilités API.
  • Cinq algorithmes principaux : Fixed Window (simple), Sliding Window Log (parfait mais coûteux), Sliding Window Counter (compromis dominant), Token Bucket (tolère bursts, pattern dominant 2026 pour APIs publiques), Leaky Bucket (lisse pour protection downstream).
  • Cinq couches d'implémentation cumulatives : edge/CDN (Cloudflare, AWS WAF), reverse proxy (Nginx, HAProxy), API gateway (Kong, AWS API Gateway), application (Redis avec Lua scripts atomiques), business logic (compteurs sémantiques par action métier).
  • Headers HTTP standardisés par RFC 9651 (mai 2024) : RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, RateLimit-Policy plus Retry-After (RFC 6585) sur HTTP 429. Compatibilité X-RateLimit-* legacy à conserver pour transition.
  • Le rate limiting per-IP seul est trivialement contourné par rotation IP. Toujours combiner per-IP + per-token utilisateur + per-business-action en couches cumulatives. Démarrer en mode observe avant blocage strict pour calibrer les seuils.

Pour aller plus loin

Questions fréquentes

  • Quelle différence entre rate limiting et throttling ?
    Les termes sont souvent utilisés indifféremment mais une distinction utile s'est établie en 2026. Rate limiting : refuse hard les requêtes au-delà du quota (HTTP 429 Too Many Requests). Throttling : ralentit les requêtes au-delà du quota (réponse delayed) sans les refuser. En pratique, la majorité des implémentations 2026 font du rate limiting strict avec HTTP 429. Le throttling pur reste utilisé pour les APIs où la disponibilité prime sur la précision (par exemple : services analytics non critiques où on préfère ralentir plutôt que perdre des données).
  • Token bucket ou sliding window : quel algorithme choisir ?
    Token bucket pour la majorité des cas API : permet des bursts courts (rafales) tout en limitant le débit moyen. Comportement intuitif pour les développeurs consommateurs (ils peuvent faire 10 requêtes en 1 seconde puis attendre). Implémentation simple côté Redis. Sliding window counter pour les cas où la précision compte et les bursts doivent être lissés (par exemple : limite stricte 100 req/min sans tolérance pour 50 req en 5 secondes). Plus exigeant en mémoire (compteurs par fenêtre) mais résultat plus prédictible. En pratique 2026 : token bucket standard pour APIs publiques, sliding window pour endpoints très sensibles (auth, paiement).
  • Faut-il rate limiter par IP, par utilisateur ou les deux ?
    Les deux, en couches cumulatives. Rate limit par IP : protection contre les bots non authentifiés et le DoS volumique au niveau réseau. Rate limit par token utilisateur : protection contre l'abus authentifié et l'enumération massive même si l'attaquant utilise plusieurs IPs. Pattern type : 100 req/sec par IP au reverse proxy + 1000 req/min par token utilisateur en API gateway + limites business spécifiques (10 transactions paiement par jour par compte) au niveau application. Les rate limits par IP seuls sont contournés trivialement par rotation IP via proxies résidentiels.
  • Comment gérer les utilisateurs derrière un NAT (entreprise) qui partagent une IP ?
    Trois approches. 1) Rate limit par IP avec quotas généreux (par exemple 10 000 req/min par IP) suffisant pour un bureau entier d'utilisateurs légitimes. 2) Combiner avec rate limit par token utilisateur (plus fin) pour ne pas dépendre de l'IP. 3) IP allowlist pour les ranges connus corporate avec quotas augmentés. Les organisations matures utilisent les trois en parallèle. Toujours tester les limites depuis un environnement représentatif (NAT enterprise simulé) avant de fixer les seuils production.
  • Quels headers HTTP retourner pour le rate limiting ?
    Standard 2026 défini par RFC 9651 (mai 2024) RateLimit Header Fields for HTTP. Trois headers principaux. RateLimit-Limit : nombre de requêtes autorisées sur la fenêtre (par exemple 100). RateLimit-Remaining : requêtes restantes dans la fenêtre courante (par exemple 42). RateLimit-Reset : secondes avant reset complet du quota (par exemple 35). Plus l'historique X-RateLimit-* legacy (sans préfixe X- mais souvent encore utilisé). Lors d'un dépassement, retourner HTTP 429 Too Many Requests avec header Retry-After (RFC 6585) indiquant délai en secondes avant retry possible. Ces headers permettent aux clients d'auto-réguler sans tâtonnement.
  • Comment éviter de bloquer les utilisateurs légitimes par erreur ?
    Trois pratiques. 1) Démarrer en mode 'observe' : rate limiting actif mais ne bloque pas, log uniquement. Ajuster les seuils sur 2 à 4 semaines de data réelle. 2) Quotas généreux par défaut, restrictifs uniquement sur endpoints sensibles (auth, paiement, exports massifs). Mieux vaut ne pas bloquer trop strict que générer faux positifs massifs. 3) Whitelist documentée pour partenaires premium et équipes internes (test, monitoring) avec API keys distinctes. Communication transparente : page status publique listant les rate limits courants (par exemple : api.example.test/docs/rate-limits) pour que les développeurs intégrateurs sachent à quoi s'attendre.

Écrit par

Naim Aouaichia

Expert cybersécurité et fondateur de Zeroday Cyber Academy

Expert cybersécurité avec un master spécialisé et un parcours hybride : développement, DevOps, DevSecOps, SOC, GRC. Fondateur de Hash24Security et Zeroday Cyber Academy. Formateur et créateur de contenu technique sur la cybersécurité appliquée, la sécurité des LLM et le DevSecOps.