API Protection

Rate Limiting

Le rate limiting protège une API contre les abus, les bugs et les clients incontrôlés. Quelques algorithmes et des headers clairs permettent de maintenir votre service disponible pour tous.

intermediate14 min readUpdated 15 sept. 2026
limit.js
js
// limit.js
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(100, "1 m"),
});

export async function handler(req, res) {
  const id = req.headers["x-api-key"] ?? req.ip;
  const { success, remaining, reset } = await ratelimit.limit(id);

  res.set("RateLimit-Remaining", String(remaining));
  res.set("RateLimit-Reset", String(Math.ceil(reset / 1000)));

  if (!success) {
    res.set("Retry-After", "60");
    return res.status(429).json({ error: "rate_limited" });
  }
  // ...handle the request
}
Statut
429 Too Many Requests
Indice
Header Retry-After
Identité
Clé, utilisateur ou IP
Algorithmes
Fenêtre, bucket
Stockage
Redis pour plusieurs instances
Objectif
Disponibilité pour tous

Pourquoi c'est important

Pourquoi limiter le débit

Protéger la disponibilité

Un seul client malveillant ou un bot de scraping peut épuiser vos ressources. Les limites garantissent que le service reste accessible pour les autres utilisateurs.

Usage équitable

Des limites par clé et par palier (tier) assurent qu'un seul appelant ne puisse pas consommer plus que sa part.

Limiter les dégâts

Les limites plafonnent également le coût des bugs, comme un client coincé dans une boucle de retry qui bombarderait votre API.

Le tableau complet

Les trois piliers du rate limiting

Identifier le client, compter ses requêtes avec un algorithme et l'informer du résultat via le bon statut et les headers appropriés.

Identité

Compter

Déterminez sur quoi la requête est comptabilisée : une clé API, un utilisateur, une IP ou une combinaison.

Algorithme

Limiter

La fenêtre fixe, la fenêtre glissante, le token bucket ou le leaky bucket déterminent comment les requêtes sont autorisées.

Réponse

Signaler

Renvoyez un code 429 avec Retry-After et des headers de rate limit pour que les clients puissent réduire leur cadence correctement.

Le rate limiting en un coup d'œil

Les concepts fondamentaux

Fenêtre fixe (Fixed window)

Un simple compteur réinitialisé à chaque intervalle ; peu coûteux mais permet des pics de trafic aux frontières de l'intervalle.

Fenêtre glissante (Sliding window)

Lisse le problème de frontière avec une meilleure précision.

Token bucket

Autorise des pics jusqu'à la taille du bucket tout en imposant un débit moyen.

Leaky bucket

Traite les requêtes à un rythme constant et met en file d'attente ou rejette l'excédent.

429 et Retry-After

La manière standard de dire « ralentissez, réessayez plus tard ».

État distribué

Partagez les compteurs dans Redis pour que les limites s'appliquent à toutes les instances.

Un bref aperçu

Des blocages IP aux limiteurs distribués

  1. 2000s

    Blocage basé sur l'IP

    Les premières défenses bloquent les IP abusives après coup.

    2000s
  2. 2010s

    Clés API et quotas

    Les API publiques introduisent des limites par clé et des quotas mensuels.

    2010s
  3. 2015

    Limiteurs Redis

    Les compteurs partagés permettent d'appliquer des limites sur plusieurs serveurs.

    15
  4. 2020

    Headers standards

    Les headers RateLimit sont proposés pour rendre les limites découvrables.

    20
  5. Aujourd'hui

    Défenses multicouches

    Limites, quotas, WAF et détection de bots fonctionnent de concert.

    Aujourd'hui

Le guide complet

Rate Limiting: Tout ce que vous devez savoir

Pourquoi limiter le débit (rate limiting)

Toute API a une capacité finie, et tous les clients ne se comportent pas correctement. Un scraper, un client buggé coincé dans une boucle de tentatives (retry loop), ou un pic de trafic légitime peuvent épuiser vos connexions à la base de données et rendre le service indisponible pour tout le monde. Le rate limiting plafonne la vitesse à laquelle un client peut effectuer des requêtes afin qu’aucun utilisateur unique ne puisse consommer l’intégralité des ressources du système.

Cela permet également de rendre les coûts prévisibles, d’imposer un usage équitable entre les tenants et les forfaits, et vous donne un levier pour freiner les abus avant qu’ils ne provoquent une panne.

Que limiter

Une limite n’a de sens que par rapport à une identité. Voici les choix les plus courants :

  • Clé API — la meilleure option pour les communications serveur à serveur et les clients tiers.
  • ID utilisateur — l’approche naturelle pour les applications avec authentification.
  • Adresse IP — une solution de repli pour le trafic anonyme, bien que plusieurs utilisateurs puissent partager la même IP.
  • Combinaison — clé plus IP, ou utilisateur plus endpoint, pour plus de précision.
  • Endpoint ou niveau (tier) — des limites plus strictes sur les opérations coûteuses comme la recherche ou les exports.

Déterminez également la portée : une limite globale, une limite par endpoint, ou les deux. Une limite globale protège le service, tandis que les limites par endpoint protègent des tâches spécifiques et gourmandes en ressources.

Algorithmes

Quatre algorithmes couvrent pratiquement tous les besoins.

Fixed window (fenêtre fixe) — compte les requêtes sur un intervalle fixe et réinitialise le compteur à la limite de l’intervalle.

limit: 100 per minute
key: client:123:2026-09-15T10:05

C’est une solution simple et peu coûteuse, mais un client peut envoyer 100 requêtes à la fin d’une fenêtre et 100 au début de la suivante, doublant ainsi efficacement le débit à la limite de la fenêtre.

Sliding window (fenêtre glissante) — compte sur les N dernières secondes plutôt que sur un bloc fixe, généralement en combinant la fenêtre actuelle et la précédente avec une moyenne pondérée. Plus fluide que la fenêtre fixe pour un coût similaire.

Token bucket (seau à jetons) — un seau se remplit à un rythme constant, et chaque requête consomme un jeton. Cela permet de courtes rafales (bursts) jusqu’à la capacité du seau tout en imposant un débit moyen, ce qui correspond au comportement réel des clients.

// token-bucket.js
const capacity = 20;
const refillPerSecond = 5;
let tokens = capacity;
let last = Date.now();

function allow() {
  const now = Date.now();
  tokens = Math.min(capacity, tokens + ((now - last) / 1000) * refillPerSecond);
  last = now;
  if (tokens < 1) return false;
  tokens -= 1;
  return true;
}

Leaky bucket (seau percé) — les requêtes entrent dans une file d’attente qui se vide à un rythme fixe. Cela lisse le trafic pour obtenir une sortie constante, ce qui est utile lorsque les systèmes en aval nécessitent une charge stable.

Répondre aux limites

Informez vos clients de la situation en utilisant des signaux standards.

HTTP/1.1 429 Too Many Requests
Retry-After: 30
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30
  • 429 Too Many Requests est le code de statut approprié.
  • Retry-After indique au client quand réessayer, soit en secondes, soit via une date.
  • Les headers RateLimit-* exposent la limite, le nombre de requêtes restantes et l’heure de réinitialisation afin que les clients puissent adapter leur rythme.

Renvoyer 200 ou ignorer silencieusement les requêtes masque le problème et entraîne des bugs clients mystérieux. Les clients bien conçus lisent Retry-After et réduisent automatiquement leur cadence.

Limitation distribuée

Si vous exécutez plusieurs instances, les compteurs doivent être partagés. Les limites en mémoire s’appliquent par instance ; ainsi, avec dix serveurs, un client bénéficie concrètement de dix fois la limite.

// redis.js
const key = `ratelimit:${apiKey}`;
const count = await redis.incr(key);
if (count === 1) await redis.expire(key, 60);

if (count > 100) {
  // reject with 429
}

Utilisez des opérations atomiques, ou une bibliothèque utilisant un script Lua, afin que les incrémentations et les expirations soient exemptes de conditions de concurrence (race conditions). Redis est le stockage habituel car il est rapide et prend en charge les scripts atomiques ainsi que l’expiration. Les API gateways et les plateformes edge peuvent appliquer les limites avant même que le trafic n’atteigne votre application, ce qui est l’endroit le plus efficace pour le faire.

Quotas vs rate limits

Ils répondent à des problématiques différentes et coexistent souvent.

  • Rate limit — la vitesse : 100 requêtes par minute.
  • Quota — la quantité : 100 000 requêtes par mois, liées à un forfait.

Un client peut rester en dessous de son rate limit tout au long du mois et tout de même épuiser son quota. Suivez les quotas séparément, généralement avec un compteur à plus longue durée de vie, et renvoyez une erreur distincte lorsqu’un quota est épuisé afin que les clients puissent faire la différence.

Éviter de nuire aux utilisateurs réels

Les limites doivent stopper les abus sans pénaliser l’utilisation normale.

  • Définissez les limites en vous basant sur le trafic mesuré, tout en prévoyant une marge pour les pics.
  • Autorisez les pics de trafic avec un système de token bucket plutôt qu’une coupure nette.
  • Utilisez des limites différentes selon le niveau d’abonnement (tier) et le point de terminaison (endpoint).
  • Excluez les health checks, les appels internes et les ressources statiques.
  • Privilégiez les ralentissements temporaires aux bannissements permanents.
  • Surveillez les taux de rejet et ajustez-les ; un pic de réponses 429 peut signifier qu’une limite est trop restrictive.

Bonnes pratiques

  • Identifiez les clients avec la clé stable la plus spécifique disponible.
  • Choisissez un algorithme adapté à la forme du trafic.
  • Retournez une erreur 429 avec Retry-After et les headers de rate limit.
  • Partagez les compteurs dans Redis ou appliquez les limites au niveau de l’edge.
  • Séparez les rate limits des quotas et exposez les deux.
  • Autorisez les bursts et définissez les limites à partir de mesures réelles.
  • Journalisez et surveillez les rejets, et configurez des alertes en cas de pics soudains.

Erreurs courantes

  • Compter par instance et multiplier la limite effective.
  • Utiliser uniquement l’IP, ce qui pénalise les utilisateurs derrière un NAT partagé.
  • Retourner un code 200 ou ignorer les requêtes silencieusement.
  • Fixer des limites si strictes que les clients normaux sont bloqués.
  • Oublier d’expirer les compteurs, entraînant des fuites de mémoire.
  • Traiter les rate limits comme un substitut à l’authentification et à l’autorisation.

Et après ?

Le rate limiting permet de maintenir une API disponible même sous forte pression. Appuyez-vous sur la conception REST et le guide HTTP, couplez-le avec le versionnage d’API dans le cadre du cycle de vie, et implémentez-le sur Node.js. Ajoutez ensuite un limiteur à l’un de vos endpoints et observez son comportement lors d’un test de charge.

Rejeter une requête

Renvoyez un code 429 avec un indice Retry-After et le nombre de requêtes restantes. Ignorer silencieusement la requête ou renvoyer un code 200 confond les clients et masque le problème.

À privilégier
HTTP/1.1 429 Too Many Requests
Retry-After: 30
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30
À éviter
HTTP/1.1 200 OK
# silently ignored or
# returns an empty body

Stocker les compteurs

Avec plusieurs instances, les compteurs doivent être partagés. Des limites en mémoire s'appliquent par instance et permettent aux clients d'atteindre N fois le débit prévu.

À privilégier
const { success } = await ratelimit.limit(key);
// shared across every instance
À éviter
const counts = new Map();
// each server has its own map,
// so the real limit is N x

Compromis

Le rate limiting est-il la bonne défense ?

Les limites protègent la disponibilité et bornent les abus, mais elles ajoutent de l'état et peuvent pénaliser des utilisateurs légitimes si l'identité ou les seuils sont erronés.

Strengths

  • Maintient le service en ligne

    Un client emballé ou un scraper ne peut pas épuiser la capacité, donc tous les autres continuent d'être servis.

  • Partage équitable

    Les limites par clé et par palier empêchent un seul appelant de consommer plus que sa part d'une ressource partagée.

  • Borne le coût des bugs

    Un client bloqué dans une boucle de réessai est contenu avant de devenir une panne ou une facture élevée.

Trade-offs

  • Nécessite un état partagé

    Des limites correctes entre instances exigent Redis ou une passerelle, ce qui ajoute une dépendance sur le chemin critique.

  • Facile à mal régler

    Des limites trop serrées ou une mauvaise identité rejettent de vrais utilisateurs, et les limites par IP pénalisent tous ceux derrière un NAT.

  • Pas une défense complète

    Limiter seul n'arrête pas les attaques distribuées, donc cela fonctionne mieux avec des quotas, des WAF et la détection de bots.

FAQ

Foire aux questions

Keep learning

Related topics from the roadmap.

$ commencer à apprendre

Prêt à apprendre Rate Limiting ?

Notre tutoriel interactif vous guide à travers Rate Limiting pas à pas — avec des quiz et du vrai code que vous pouvez exécuter dans le navigateur.