Limitation de débit et WAF devant des conteneurs Docker sans bloquer les vrais utilisateurs

Cet article vous a aidé ?

Tout fonctionne en staging. Puis la production est découverte—par des clients, par des scrapers, par des “chercheurs en sécurité”, et par tout ce qui vit dans l’espace d’adresses IP public ce jour-là. Vous ajoutez un WAF et une limitation de débit. Les alertes se calment. Et ensuite la file de support s’enflamme : « Je n’arrive pas à me connecter », « Le paiement échoue », « L’API renvoie 429 », « L’IP de mon bureau est bloquée », « Votre site déteste les hôtels ».

Ceci est la partie que personne ne vend dans la démo produit : les limitations de débit et les WAF ne sont pas des garde-fous, ce sont des volants. Si vous ne pilotez pas—si vous n’observez pas, n’ajustez pas et ne modélisez pas le comportement réel des utilisateurs—vous allez absolument bloquer ceux qui paient vos factures, pendant que les bots changent calmement d’IP et continuent.

Un modèle mental opérationnel : WAF vs limitation de débit vs « juste un reverse proxy »

Posez les mots à la mode une minute et pensez en termes de modes de défaillance.

Limitation de débit

La limitation de débit concerne la protection de capacité et le coût d’abus. Elle répond : « Combien de requêtes autorisons‑nous d’un seul acteur dans une fenêtre ? » Elle ne répond pas : « Cette requête est‑elle malveillante ? » Elle n’empêche pas non plus automatiquement l’abus distribué (un botnet peut rester poli par IP tout en vous fondant en agrégé).

WAF (pare‑feu applicatif web)

Un WAF concerne le risque d’entrée. Il répond : « Cette requête ressemble‑t‑elle à une tentative d’exploitation ou à un abus de protocole ? » C’est du matching de motifs et de la détection d’anomalies—parfois bon, parfois hilarantement mauvais. Les WAF réduisent le bruit d’attaques courantes (sprays SQLi, probes de traversal de chemin), mais ils punissent aussi le trafic inhabituel mais légitime, comme des API avec des chaînes de requête étranges ou des utilisateurs derrière des proxies d’entreprise.

Reverse proxy

Le reverse proxy est votre agent de circulation : terminaison TLS, routage, normalisation d’en‑têtes, pooling de connexions, et l’endroit où vous pouvez implémenter à la fois du filtrage de type WAF et de la limitation de débit. Si vous utilisez Docker, un reverse proxy n’est pas optionnel à moins d’aimer exposer chaque port de conteneur sur Internet comme si c’était 2014.

Opinion : Placez la logique de limitation de débit et du WAF à la périphérie que vous pouvez observer et versionner. Cela signifie un proxy que vous possédez (Nginx/HAProxy/Traefik) ou une edge gérée (CDN/fournisseur WAF) où vous avez toujours des logs et pouvez tester les changements. La « sécurité boîte noire » est la manière dont vous vous retrouvez à déboguer la production à l’aveugle.

Une citation à garder collée à votre écran : « L’espoir n’est pas une stratégie. » — attribué à divers opérateurs ; traitez‑la comme une idée paraphrasée, pas une écriture.

Faits et contexte historique (ce qui explique la douleur d’aujourd’hui)

  • Les WAF sont devenus courants après les exploits web du début des années 2000 : OWASP a démarré en 2001 ; le premier OWASP Top 10 est apparu en 2003 et a façonné les jeux de règles WAF pendant deux décennies.
  • ModSecurity a commencé comme module Apache (2002) : il a popularisé le modèle « moteur de règles », qui est ensuite apparu dans Nginx, les contrôleurs ingress et les WAF gérés.
  • La limitation de débit est antérieure au web : les algorithmes token bucket et leaky bucket viennent du travail télécom/réseau des années 1980 ; ce sont encore les primitives de base aujourd’hui.
  • HTTP/1.1 keep-alive a changé la donne : une fois que les clients pouvaient réutiliser des connexions, les limites par connexion sont devenues inutiles, et les contrôles par requête/par identité ont pris de l’importance.
  • Le NAT est partout : les opérateurs mobiles et les réseaux d’entreprise mettent de plus en plus des milliers d’utilisateurs derrière quelques adresses egress, donc les limites « par IP » ont commencé à punir des foules innocentes.
  • Les CDN ont déplacé le problème du « véritable IP client » : une fois le trafic terminé au niveau d’un CDN/WAF, votre origin voit l’IP du CDN à moins que vous ne fassiez confiance et n’analysiez explicitement les en‑têtes forwardés.
  • La multiplexion HTTP/2 permet des taux élevés de requêtes par connexion : si vous limitez seulement les connexions, un seul client peut toujours inonder par de nombreux streams.
  • Les conteneurs ont rendu la « périphérie » mouvante : à l’époque des VM, le load balancer était stable ; avec les conteneurs, les équipes essaient sans cesse de coller la sécurité dans le conteneur applicatif. C’est mignon. Ne le faites pas.

Blague #1 : Un jeu de règles WAF est comme une plante d’intérieur—ignorez‑le pendant un mois et il mourra, et il pourrait bien vous prendre votre week‑end.

Schémas d’architecture recommandés (et quand choisir chacun)

Modèle A : CDN/fournisseur WAF → reverse proxy → services Docker

C’est la configuration « supervision adulte ». Votre edge géré absorbe les déchets volumétriques et gère l’atténuation basique des bots. Votre reverse proxy applique un routage précis, des limites applicatives fines, et émet des logs que vous pouvez corréler.

À utiliser quand : vous êtes exposé sur Internet, vous avez des endpoints de connexion/paiement/API, et vous tenez à ne pas être réveillé par un scan global qui vous met à genoux.

Risque principal : faire une confiance incorrecte aux en‑têtes forwardés. Si vous traitez tout X-Forwarded-For comme évangile, des attaquants pourront usurper la « véritable IP client » et contourner les limites par IP.

Modèle B : Reverse proxy avec module WAF (ex. ModSecurity/Coraza) → services Docker

Cela vous donne un contrôle au niveau des règles et garde les logs localement. C’est aussi lourd à opérer : les règles nécessitent du tuning et vous êtes responsable des performances.

À utiliser quand : la conformité exige des contrôles autogérés, ou vous ne pouvez pas placer une edge gérée devant pour des raisons business.

Risque principal : burn CPU et faux positifs si vous activez un niveau de paranoïa CRS complet sans comprendre votre propre trafic.

Modèle C : Limitation au niveau applicatif dans le conteneur

Utile pour la logique « un utilisateur ne doit pas spammer un endpoint » (ex. réinitialisation de mot de passe). Mauvais comme protection primaire.

À utiliser quand : vous avez besoin de limites conscientes de l’identité (ID compte, clé API) et vous ne pouvez pas l’exprimer proprement au proxy.

Risque principal : chaque réplique limite indépendamment sauf si vous utilisez un magasin partagé (Redis, etc.). Les attaquants font du round‑robin et vous contournent.

Ce que je recommande pour la plupart des équipes Docker

Faites les deux : contrôles en edge et à l’origine :

  • À l’edge : mitigation grossière des bots et blindage volumétrique.
  • Au reverse proxy : limites précises par route et contrôles WAF basiques adaptés à votre app.
  • Dans l’app : contrôles ciblés et conscients de l’identité pour les workflows sensibles.

Contrôles en couches. Mesurés. Journalisés. Rétrofitables.

L’identité est difficile : les IP mentent, les utilisateurs se déplacent et le NAT ruine votre journée

La plupart des pannes auto‑infligées par WAF/limitation de débit proviennent d’une hypothèse : « l’adresse IP équivaut à un utilisateur ». En 2026, cette hypothèse est suffisamment souvent fausse pour vous nuire.

Pourquoi les limites basées sur l’IP comptent encore

Elles sont simples et bon marché. Elles arrêtent les scanners les plus paresseux. Elles réduisent le bruit de fond. Mais ce n’est pas de l’équité. C’est un instrument grossier.

Où les limites par IP échouent

  • Carrier‑grade NAT (réseaux mobiles) : des milliers d’appareils derrière quelques adresses IP.
  • Proxies d’entreprise : tout un bureau apparaît comme une seule adresse. Félicitations, vous venez de limiter la comptabilité.
  • Relais de confidentialité et VPN : des utilisateurs légitimes peuvent paraître « bot », et des bots peuvent paraître « légitimes ».
  • IPv6 : les utilisateurs peuvent avoir de nombreuses adresses ; une logique naïve par IP peut être contournée par simple rotation d’adresses.

Des identités meilleures que « IP source »

Choisissez l’identifiant le plus fort que vous pouvez valider de façon fiable :

  • Clé API (meilleure pour les APIs B2B)
  • ID de compte (après authentification)
  • Cookie de session (prudent avec les bots qui stockent des cookies)
  • Empreinte d’appareil (utile, mais délicate et sensible en matière de confidentialité)
  • Sous‑réseau IP (parfois plus juste que l’IP exacte, parfois pire)

Règle pratique : limitez par IP pour les endpoints non authentifiés, puis passez aux limites basées sur l’identité une fois l’utilisateur authentifié. C’est là que se trouve l’équité.

Concevoir des limites de débit sensées qui n’embrasent pas les vrais utilisateurs

La limitation de débit n’est pas une question de choisir un nombre. Il s’agit de modéliser le comportement : flux humains, tentatives de l’application, instabilité mobile, et intégrations tierces qui se comportent comme des écureuils caféinés.

Commencez par des classes d’endpoint, pas une limite globale

  • Connexion : faible débit, haute sensibilité. Ajoutez délai progressif et contrôles anti‑bots forts.
  • Réinitialisation de mot de passe / OTP : débit très faible, audit strict.
  • Recherche : moyen à élevé, mais protégez les caches et bases de données en backend.
  • Assets statiques : généralement gérés par le CDN ; ne gaspillez pas le budget de limitation d’origine ici.
  • Endpoints API bulk : autorisez des rafales, imposez des taux soutenus, et exigez des clés.
  • Webhooks entrants : limitez par identité partenaire, pas par IP, et autorisez les retries.

Choisissez un algorithme qui correspond à votre trafic

Token bucket est souvent le bon choix : autorisez de courtes rafales (chargements de page, démarrage d’app), limitez l’abus soutenu. Les limites en fenêtre fixe sont simples mais provoquent des effets falaise : les utilisateurs se font bloquer parce qu’ils ont cliqué « rafraîchir » au mauvais moment.

Rendez les réponses 429 utiles

Si vous renvoyez HTTP 429, incluez Retry-After (secondes) ou un schéma d’en‑têtes de limitation de débit que vous respectez réellement. Les clients bien conçus reculeront. Les mauvais clients l’ignoreront, ce qui est acceptable ; vous protégez tout de même votre backend.

Ne limitez pas les healthchecks comme s’ils étaient des attaquants

Si votre orchestrateur ou votre moniteur externe obtient des 429, vous vous êtes auto‑piégé : il va réessayer plus fort, et maintenant vous êtes “attaqué” par vos propres outils.

Décidez ce que « bloqué » signifie

Bloquer peut vouloir dire :

  • Rejet dur (403/429) : mieux pour les comportements notoirement mauvais.
  • Challenge doux : CAPTCHA ou défi JS à la périphérie ; utile pour le trafic suspect mais pas certain.
  • Dégrader : servir des résultats en cache/périmés, réduire les fonctionnalités coûteuses, ou mettre en file d’attente le travail.

Tuning du WAF sans superstition

Un jeu de règles WAF est une hypothèse. Votre trafic est l’expérience. Traitez le tuning comme de l’ingénierie, pas comme du folklore.

Exécutez en mode détection uniquement d’abord

Activez le WAF pour journaliser ce qu’il aurait bloqué. Rassemblez au moins quelques jours de trafic, incluant les heures de pointe métier et les jobs batch. Puis ajustez des exceptions basées sur les preuves.

Connaissez vos zones à faux positifs élevés

  • APIs JSON avec payloads imbriqués : peuvent déclencher des règles « anomalie corps de requête ».
  • GraphQL : les chaînes de requête ressemblent souvent à des motifs d’injection.
  • Filtres de recherche : les utilisateurs collent des caractères bizarres ; les WAF paniquent.
  • Endpoints d’upload : parsing multipart et seuils de taille.
  • URLs de redirection/callback : des URLs encodées dans des paramètres ressemblent à des probes SSRF.

Stratégie d’exception : étroite, journalisée, revue

Ne désactivez pas des classes entières de règles globalement parce qu’un endpoint est bruyant. Taillez des exceptions par :

  • Chemin (route exacte)
  • Méthode (POST vs GET)
  • Nom du paramètre (autoriser l’étrangeté uniquement dans q pour la recherche, pas dans redirect)
  • Content-type (JSON vs form)
  • Authentifié vs non authentifié

La performance du WAF compte

L’inspection WAF peut être gourmande en CPU. Si votre proxy est saturé, vous verrez la latence augmenter puis une vague de timeouts. Cela ressemble à un incident applicatif, mais c’est votre couche de sécurité qui étrangle l’hôte.

Blague #2 : La façon la plus rapide de trouver une règle WAF non testée est de la déployer un vendredi après‑midi. C’est aussi la façon la plus rapide de rencontrer votre rotation on‑call.

Tâches pratiques : commandes, sorties et décisions (12+)

Ce sont le genre de tâches que vous lancez quand des utilisateurs signalent des blocages, que des bots montent en flèche, ou quand vous déployez des contrôles pour la première fois. Les commandes sont écrites pour un hôte Docker avec un conteneur reverse proxy (Nginx/Traefik/HAProxy) et des outils Linux typiques.

Tâche 1 : Confirmer quels ports sont réellement exposés

cr0x@server:~$ docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}'
NAMES            IMAGE                 PORTS
edge-nginx       nginx:1.25            0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
app-api          myco/api:2026.01      8080/tcp
app-web          myco/web:2026.01      3000/tcp
redis            redis:7               6379/tcp

Ce que cela signifie : seul le proxy edge publie 80/443 vers le monde. Les conteneurs applicatifs sont internes uniquement.

Décision : si vous voyez 0.0.0.0:8080->8080 sur un conteneur applicatif, corrigez‑le. Les limites et WAF n’aident pas si les attaquants contournent le proxy.

Tâche 2 : Vérifier que le proxy est le seul écouteur sur 80/443

cr0x@server:~$ sudo ss -lntp | egrep ':80|:443'
LISTEN 0      4096         0.0.0.0:80        0.0.0.0:*    users:(("docker-proxy",pid=2114,fd=4))
LISTEN 0      4096         0.0.0.0:443       0.0.0.0:*    users:(("docker-proxy",pid=2121,fd=4))

Ce que cela signifie : Docker publie des ports, probablement mappés au conteneur proxy.

Décision : si d’autres processus écoutent ces ports, vous pouvez avoir une voie de contournement ou une collision de ports. Corrigez avant d’ajuster les règles WAF.

Tâche 3 : Vérifier si vous faites confiance correctement aux en‑têtes forwardés

cr0x@server:~$ docker exec -it edge-nginx nginx -T 2>/dev/null | egrep -n 'real_ip|set_real_ip_from|X-Forwarded-For' | head -n 30
45:    real_ip_header X-Forwarded-For;
46:    set_real_ip_from 172.18.0.0/16;
47:    real_ip_recursive on;

Ce que cela signifie : Nginx est configuré pour traiter X-Forwarded-For comme l’IP client, mais seulement quand l’émetteur immédiat est dans 172.18.0.0/16 (votre réseau Docker).

Décision : bon. Si vous voyez set_real_ip_from 0.0.0.0/0; vous laissez des attaquants usurper leur IP et esquiver les limites. Corrigez immédiatement.

Tâche 4 : Confirmer quelle IP l’app voit (le contrôle « pourquoi les utilisateurs sont groupés ? »)

cr0x@server:~$ docker logs --tail=20 app-api
2026-01-03T08:18:22Z INFO request method=GET path=/v1/me remote=172.18.0.5 xff="198.51.100.23"
2026-01-03T08:18:22Z INFO request method=POST path=/v1/login remote=172.18.0.5 xff="203.0.113.10, 172.18.0.1"

Ce que cela signifie : le pair TCP de l’app est le proxy, mais elle reçoit aussi X-Forwarded-For. La chaîne indique plusieurs sauts.

Décision : assurez‑vous que votre framework applicatif utilise la bonne logique d’IP client et ne fait confiance qu’à votre proxy. Sinon, les limites en‑app seront injustes ou contournables.

Tâche 5 : Identifier les principaux émetteurs à la périphérie (par IP) dans les access logs

cr0x@server:~$ sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head
  9123 203.0.113.77
  5110 198.51.100.23
  4022 203.0.113.10
  1889 192.0.2.44

Ce que cela signifie : ces IP génèrent beaucoup de requêtes. Pas forcément malveillant ; cela peut être du NAT ou un partenaire.

Décision : recoupez avec l’user‑agent, les chemins et les codes de réponse avant de bloquer. Un volume élevé seul n’est pas une preuve.

Tâche 6 : Trouver quels endpoints déclenchent des 429

cr0x@server:~$ sudo awk '$9==429 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head
  644 /v1/login
  201 /v1/search
   88 /v1/password-reset

Ce que cela signifie : votre limite actuelle est principalement atteinte sur login et search.

Décision : les 429 sur login peuvent être bons (contrôle de bots) ou mauvais (utilisateurs réels derrière NAT). Les 429 sur search signifient souvent que votre limite est trop basse pour le comportement UI ou que le frontend réessaie trop agressivement.

Tâche 7 : Vérifier si les 429 sont corrélés à un user‑agent particulier (signature bot)

cr0x@server:~$ sudo awk '$9==429 {print $12}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head
  701 "-" 
  133 "python-requests/2.31.0"
   67 "Mozilla/5.0"

Ce que cela signifie : beaucoup de 429 ont un user‑agent vide/absent, ce qui est courant pour des scripts.

Décision : vous pouvez appliquer des limites plus strictes ou des challenges pour le trafic avec UA vide, tout en faisant attention à ne pas casser des clients légitimes (quelques outils d’entreprise sont… minimalistes).

Tâche 8 : Confirmer si votre proxy est lié CPU pendant l’inspection WAF

cr0x@server:~$ docker stats --no-stream edge-nginx
CONTAINER ID   NAME        CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O   PIDS
a1b2c3d4e5f6   edge-nginx  186.45%   612MiB / 2GiB         29.88%    1.8GB / 2.1GB     0B / 0B    38

Ce que cela signifie : presque 2 cœurs sont saturés dans le conteneur proxy. Ça peut venir du parsing WAF, de règles lourdes en regex, ou juste d’un trafic trop important.

Décision : si les pics CPU coïncident avec des requêtes bloquées et de la latence, ajustez les règles WAF (réduire la portée), ajoutez du caching/CDN, ou scalez des réplicas de proxy derrière un load balancer.

Tâche 9 : Vérifier les symptômes conntrack et backlog de sockets (hôte edge sous pression)

cr0x@server:~$ sudo sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_count = 249812
net.netfilter.nf_conntrack_max = 262144

Ce que cela signifie : conntrack est proche de sa limite. Les nouvelles connexions peuvent échouer ou subir des timeouts étranges.

Décision : augmentez prudemment le max conntrack, réduisez le churn de connexions (keep‑alive), et assurez‑vous que la limitation de débit ne pousse pas les clients vers des tempêtes de reconnexions.

Tâche 10 : Inspecter les logs WAF pour la règle exacte qui bloque des utilisateurs réels

cr0x@server:~$ sudo tail -n 20 /var/log/modsecurity/audit.log
--b7c1f3-A--
[03/Jan/2026:08:20:11 +0000] WQx8cQAAAEAAAB9J 198.51.100.23 54022 172.18.0.10 443
--b7c1f3-B--
GET /v1/search?q=%2B%2B%2B HTTP/1.1
Host: api.example.internal
User-Agent: Mozilla/5.0
--b7c1f3-F--
HTTP/1.1 403
--b7c1f3-H--
Message: Access denied with code 403 (phase 2). Matched "Operator `Rx' with parameter `(?:\bunion\b|\bselect\b)'" against variable `ARGS:q' (Value: '+++') [id "942100"]

Ce que cela signifie : la règle 942100 s’est déclenchée sur le paramètre de recherche q. L’utilisateur a cherché « +++ » et a été traité comme une tentative d’injection SQL.

Décision : ajoutez une exception ciblée pour ARGS:q sur /v1/search (ou baissez le niveau de paranoïa pour cet endpoint). Ne désactivez pas globalement l’ensemble de règles SQLi.

Tâche 11 : Valider que votre clé de limitation est bien ce que vous croyez

cr0x@server:~$ docker exec -it edge-nginx nginx -T 2>/dev/null | egrep -n 'limit_req_zone|limit_req' | head -n 40
120: limit_req_zone $binary_remote_addr zone=perip:20m rate=10r/s;
215: location /v1/login {
216:     limit_req zone=perip burst=20 nodelay;
217:     proxy_pass http://app-api:8080;
218: }

Ce que cela signifie : la clé est l’IP client ($binary_remote_addr). Si votre « véritable IP » est incorrecte, cela regroupe beaucoup d’utilisateurs dans un seul seau.

Décision : confirmez d’abord la gestion de la véritable IP. Si beaucoup d’utilisateurs légitimes partagent des IPs (NAT d’entreprise), déplacez les limites de connexion vers une combinaison IP + cookie ou ajoutez des limites basées sur l’identité dans l’app.

Tâche 12 : Reproduire un 429 depuis votre poste pour confirmer le comportement et les en‑têtes

cr0x@server:~$ for i in {1..40}; do curl -sk -o /dev/null -w "%{http_code} %{time_total}\n" https://example.com/v1/login; done | tail
200 0.031122
200 0.030881
429 0.000942
429 0.000913
429 0.000901

Ce que cela signifie : après quelques requêtes, vous atteignez la limite et recevez des 429 immédiats.

Décision : vérifiez si le 429 inclut Retry-After. Sinon, ajoutez‑le. Si les clients martèlent après un 429, vous verrez une boucle de rétroaction.

Tâche 13 : Vérifier que l’application ne génère pas de retries internes ressemblant à de l’abus

cr0x@server:~$ docker logs --since=10m app-web | egrep -i 'retry|429|too many' | tail -n 20
2026-01-03T08:14:02Z WARN api_call failed status=429 retry_in_ms=200
2026-01-03T08:14:02Z WARN api_call failed status=429 retry_in_ms=200
2026-01-03T08:14:03Z WARN api_call failed status=429 retry_in_ms=200

Ce que cela signifie : le frontend réessaie vite (200ms) sur 429, ce qui est l’inverse de ce que vous souhaitez.

Décision : corrigez la logique de backoff client (exponentiel, respecter Retry-After). Sinon votre limite devient une tempête de retries.

Tâche 14 : Confirmer le point de terminaison TLS et le protocole (HTTP/2 peut changer les schémas de charge)

cr0x@server:~$ echo | openssl s_client -alpn h2 -connect example.com:443 2>/dev/null | egrep 'ALPN protocol|Protocol'
Protocol  : TLSv1.3
ALPN protocol: h2

Ce que cela signifie : les clients négocient HTTP/2. La multiplexion peut augmenter la concurrence de requêtes par client.

Décision : assurez‑vous que vos limites sont par identité et par requête, pas par connexion. Si vous ne plafonnez que les connexions, HTTP/2 passera au travers.

Tâche 15 : Vérifier les chemins réseau Docker (assurer qu’il n’existe pas de route directe vers les apps depuis l’extérieur)

cr0x@server:~$ docker network inspect bridge --format '{{json .IPAM.Config}}'
[{"Subnet":"172.17.0.0/16","Gateway":"172.17.0.1"}]

Ce que cela signifie : vos conteneurs sont sur un bridge Docker privé. C’est bien, mais ne confondez pas « IP privée » et « non atteignable ».

Décision : confirmez que les règles de pare‑feu empêchent l’accès entrant aux ports publiés des conteneurs, et évitez de publier les ports applicatifs du tout.

Mode opératoire de diagnostic rapide

Quand un vrai utilisateur est bloqué (ou que vos graphiques ressemblent à un sismographe), ne commencez pas par éditer les règles. Commencez par localiser la couche qui fait le mal.

Première étape : déterminer quel type de blocage c’est

  • 403 : probablement WAF/ACL/listes de blocage.
  • 429 : limitation de débit.
  • 5xx : plantage amont, surcharge, ou timeouts proxy.
  • Timeouts clients : conntrack/backlog/problèmes de handshake TLS, ou proxy CPU saturé.

Deuxième étape : trouver où la décision a été prise

  • Logs/événements de l’edge provider (si vous avez un CDN/WAF).
  • Access logs du reverse proxy : code de statut, temps de requête, temps upstream.
  • Logs d’audit WAF : ID de règle et cible de la correspondance.
  • Logs applicatifs : la requête a‑t‑elle atteint l’app ?

Troisième étape : valider l’identité et les en‑têtes

  • L’IP client est‑elle correcte (chaîne X-Forwarded-For) ?
  • Faites‑vous confiance uniquement aux proxies connus ?
  • La clé de limitation n’effondre‑t‑elle pas beaucoup d’utilisateurs dans un seul seau ?

Quatrième étape : vérifier la saturation des ressources

  • CPU et mémoire du proxy (le parsing WAF et les regex peuvent faire monter le CPU).
  • Conntrack proche du max (churn de connexions et SYN floods).
  • Latence amont (base de données/cache) causant des tempêtes de retries.

Cinquième étape : atténuer en toute sécurité

  • Basculer le WAF en détection‑seulement temporairement si les faux positifs sont sévères.
  • Augmenter la capacité de burst pour les endpoints utilisateur pendant l’investigation.
  • Appliquer des allowlists temporaires pour IPs partenaires connues avec une date d’expiration.
  • Ralentir ou challenger les classes de trafic suspectes (UA vide, ASN connus mauvais si vous avez de la confiance).

Trois mini-récits d’entreprise issus du terrain

Incident causé par une mauvaise hypothèse : « Par IP = par utilisateur »

L’entreprise était de taille moyenne, B2C, avec une base mobile importante et un endpoint de connexion qui s’est fait marteler par du credential stuffing. Ils ont mis une limitation Nginx sur /login : 5 requêtes par minute par IP. Simple. Ça a fonctionné instantanément dans leurs tests synthétiques. Le trafic bot a chuté, et le graphique est redevenu civilisé.

Deux jours plus tard, le support client ouvre un incident parce que les échecs de connexion ont explosé dans une région spécifique. Les ingénieurs regardent le tableau de bord du WAF et ne voient rien d’évident. L’origine renvoyait des 429. « OK », quelqu’un a dit, « les bots continuent d’essayer. » Mais les user‑agents étaient des navigateurs normaux, et les requêtes avaient des tokens CSRF valides.

La pièce manquante était la réalité réseau : un gros opérateur mobile dans cette région utilisait un NAT agressif. Un grand nombre d’utilisateurs légitimes partageaient un petit pool d’IP egress. Donc au moment de pointe, l’IP NAT atteignait la limite. Des milliers de personnes se disputaient cinq connexions par minute.

La correction n’a pas été « retirer la limitation ». Ce fut « arrêter de prétendre que l’IP = humain ». Ils ont changé les limites non authentifiées pour qu’elles soient plus élevées avec une rafale, ajouté des clés basées sur cookie d’appareil à la périphérie, et appliqué des limites plus strictes après des échecs répétés de connexion par compte. Ils ont aussi ajouté un challenge doux pour les patterns de login suspects. Le credential stuffing est resté contenu, et les connexions légitimes ont récupéré.

Optimisation qui a mal tourné : cacher la mauvaise chose au mauvais endroit

Une autre équipe voulait réduire la charge backend et améliorer la latence. Ils ont introduit un caching agressif au reverse proxy pour plusieurs endpoints GET d’API. Bonne idée en général. Puis ils ont voulu être malins : ils ont mis en cache aussi certaines réponses d’erreur, « pour protéger le backend pendant les pics ». Cela incluait des 429 issus de la limitation de débit.

Pendant un léger pic de trafic, un sous‑ensemble d’utilisateurs a commencé à recevoir des 429. Le proxy a caché ces 429 pendant 30 secondes. Maintenant chaque utilisateur touchant cet endpoint avec cette clé de cache (qui incluait un ensemble d’en‑têtes trop large) recevait le 429 mis en cache, même si lui‑même était largement sous la limite.

L’incident ressemblait à « la limite est trop stricte », mais ce n’était pas le cas. La couche de cache a amplifié le rayon d’impact d’un throttle localisé en panne utilisateur. Ils avaient créé un destin partagé entre clients non liés.

Le rollback fut immédiat : ne jamais cacher les 429 au proxy sauf si vous avez un design très délibéré, une clé de cache correcte, et une forte raison. Si vous essayez de protéger les upstreams, utilisez des files d’attente, des disjoncteurs, ou servez du contenu périmé—pas des throttles en cache.

Pratique ennuyeuse mais correcte qui a sauvé la mise : déploiement en étapes avec détection seulement et kill switch

Un service lié aux paiements avait une exigence de sécurité pour ajouter des contrôles WAF devant leurs APIs hébergées sur Docker. Ils avaient déjà été brûlés par le « on active et on prie », donc ils ont fait quelque chose de profondément peu sexy : une phase de deux semaines en détection seulement avec une revue quotidienne.

Chaque matin, un SRE et un ingénieur applicatif regardaient les règles les plus déclenchées, puis comparaient avec des échantillons de requêtes réelles. Ils taguaient chaque hit comme « malveillant », « inconnu » ou « faux positif », et n’écrivaient des exceptions que lorsqu’ils pouvaient expliquer le trafic. Ils avaient aussi un feature flag qui pouvait couper l’application de la contrainte en un reload de config.

Le jour de l’enforcement, ils l’ont déployé par classe de endpoints : routes admin d’abord (faible diversité d’utilisateurs), puis APIs partenaires (identifiées par clé), puis endpoints publics. Ils ont surveillé les taux de 403 et 429, et avaient un seuil clair de rollback.

Ce même après‑midi, une intégration partenaire légitime a commencé à échouer parce qu’elle envoyait des champs JSON exceptionnellement longs qui déclenchaient une règle d’anomalie de taille de corps. Parce qu’ils avaient un historique en détection et un kill switch, ils ont pu cibler une exception pour cette route partenaire et ce paramètre, recharger, et passer à autre chose. Pas de drame. Pas de war room. Juste du travail.

Erreurs courantes : symptôme → cause racine → correction

1) Les utilisateurs derrière bureaux/hôtels ne peuvent pas se connecter (beaucoup de 429)

Symptôme : plaintes depuis des réseaux d’entreprise ; les logs montrent beaucoup de 429 depuis une même IP avec des UA de navigateurs normaux.

Cause racine : limitation par IP sur les endpoints non authentifiés ; NAT regroupe beaucoup d’utilisateurs.

Correction : augmentez la rafale, limitez par cookie/token d’appareil, et ajoutez des limites par compte pour les échecs de connexion en app. Gardez des limites par IP, mais moins punitives.

2) « Tout est bloqué » après activation du WAF

Symptôme : flambée soudaine de 403 ; l’app voit moins de requêtes ; les logs WAF montrent des règles courantes déclenchées sur des payloads normaux.

Cause racine : activation en enforcement sans baseline de détection ; niveau de paranoïa trop élevé ; règles appliquées uniformément à toutes les routes.

Correction : revenir en detection-only, tuner par endpoint, ajouter des exclusions étroites, puis réactiver progressivement.

3) La limitation de débit semble inefficace contre les bots

Symptôme : la charge backend reste élevée ; les throttles par IP se déclenchent mais le trafic bot continue.

Cause racine : attaque distribuée avec rotation d’IP ; ou le bot utilise beaucoup d’IP sous le seuil.

Correction : ajoutez des limites basées sur l’identité (clés API, sessions), des challenges bots à l’edge, et des limites agrégées (caps de concurrence globale) plus du caching.

4) Des utilisateurs au hasard sont bloqués par des erreurs « injection SQL » sur la recherche

Symptôme : 403 sur les endpoints de recherche ; logs WAF montrant des règles SQLi sur le paramètre de requête.

Cause racine : règles CRS génériques interprétant la syntaxe de recherche comme une SQLi.

Correction : restreindre la portée de l’inspection ou désactiver des IDs de règle spécifiques pour ce paramètre/chemin ; garder les règles SQLi pour les endpoints sensibles.

5) Après ajout de limites, la latence augmente et des timeouts apparaissent

Symptôme : pic de latence p95 ; CPU proxy élevé ; des erreurs 504/499.

Cause racine : surcharge d’inspection WAF ou règles lourdes en regex ; possible churn de connexions si les clients réessaient.

Correction : réduire la portée d’inspection (inspecter le corps uniquement où nécessaire), optimiser les règles, scaler le proxy, et imposer un backoff client sensé avec Retry-After.

6) Des utilisateurs contournent les limites en usurpant X-Forwarded-For

Symptôme : les logs montrent des IP clients très variables depuis le même pair TCP ; la limitation ne capture pas les clients abusifs.

Cause racine : le proxy fait confiance aux en‑têtes forwardés d’origine non fiable.

Correction : configurez des plages d’IP proxy de confiance uniquement ; supprimez les en‑têtes forwardés entrants à la périphérie publique et réajoutez‑les vous‑mêmes.

7) Les webhooks échouent car les retries du partenaire sont bloqués

Symptôme : endpoint webhook entrant renvoie 429 ; le partenaire signale des événements manquants.

Cause racine : endpoint webhook limité par IP ; les partenaires réessaient en rafales après timeouts.

Correction : limitez par identité partenaire (secret partagé, token), autorisez de plus grandes rafales, et traitez de manière asynchrone avec des clés d’idempotence.

8) « Notre monitoring dit que nous sommes down » mais les utilisateurs vont bien (ou inversement)

Symptôme : les checks externes sont bloqués, mais les utilisateurs réels ne le sont pas ; ou les utilisateurs sont bloqués et les checks non.

Cause racine : les moniteurs ont des IPs/en‑têtes distincts et sont traités différemment ; exceptions WAF pour les moniteurs ; limites sur les endpoints de santé.

Correction : traitez le monitoring comme un client de première classe : IDs stables, règles d’autorisation explicites, et endpoints séparés pour des checks profonds.

Listes de vérification / plan étape par étape

Déploiement étape par étape qui évite les pannes auto‑infligées

  1. Verrouillez l’exposition : seul le proxy publie des ports ; les conteneurs sont internes.
  2. Normalisez l’identité client : configurez les IPs proxy de confiance ; définissez la véritable IP client correctement ; supprimez les en‑têtes usurpables depuis l’edge public.
  3. Activez la journalisation d’abord : access logs avec timing upstream ; logs d’audit WAF ; logs applicatifs structurés.
  4. Activez le WAF en detection‑only : collectez au moins plusieurs jours ; incluez heures de pointe et jobs batch.
  5. Classez les endpoints : login, recherche, checkout, admin, webhooks, APIs bulk. Chacun a sa politique.
  6. Implémentez des limites par endpoint : commencez avec une rafale généreuse ; imposez un taux soutenu ; renvoyez 429 avec Retry-After.
  7. Introduisez des limites basées sur l’identité : clé API/ID compte/session après auth ; par‑IP uniquement pour la protection non authentifiée ou grossière.
  8. Créez des exceptions étroites : par chemin + paramètre + méthode. Journalisez chaque motif d’exception.
  9. Ajoutez un kill switch : un flag de configuration pour désactiver l’enforcement ou réduire la paranoïa sans redeployer les apps.
  10. Déployez progressivement : admin/interne → APIs partenaires → endpoints publics.
  11. Définissez des seuils alignés SLO : définissez quels taux de 403/429 sont acceptables avant rollback.
  12. Répétez la réponse à incident : pouvez‑vous identifier la couche bloquante en moins de 5 minutes ?

Checklist opérationnelle pour la maintenance continue

  • Revue hebdomadaire des règles WAF les plus déclenchées et des endpoints avec le plus de 429.
  • Confirmer la configuration de la véritable IP après tout changement réseau/CDN.
  • Suivre les faux positifs comme des bugs avec propriétaires et dates d’expiration sur les allowlists temporaires.
  • Tester les flows login/recherche depuis des réseaux mobiles et egresss d’entreprise (ou au moins des proxies se comportant de la même façon).
  • S’assurer que les SDK clients respectent Retry-After et le backoff exponentiel.
  • Planifier la capacité CPU du proxy pour l’inspection WAF ; traitez‑le comme une charge réelle.

FAQ

1) Dois‑je mettre le WAF dans le conteneur applicatif ?

Non, pas comme contrôle principal. Placez‑le au reverse proxy ou à l’edge gérée où vous pouvez centraliser les politiques, journaliser de façon cohérente, et éviter la dérive par réplique.

2) La limitation par IP est‑elle toujours mauvaise ?

Elle est utile et bon marché. Elle est aussi injuste. Utilisez‑la comme coquille extérieure grossière, puis utilisez de meilleures identités (cookie/session/clé API/compte) quand c’est possible.

3) Comment éviter de bloquer les utilisateurs mobiles derrière un NAT ?

Autorisez des rafales, ne mettez pas des plafonds minuscules par minute, et passez à une clé basée sur cookie/session dès que possible. Pour le login, ajoutez des limites par compte pour les tentatives échouées.

4) Quelle est la différence entre 403 et 429 pour ces contrôles ?

Utilisez 429 pour « ralentissez, vous dépassez votre quota ». Utilisez 403 pour « nous ne servirons pas cette requête » (WAF/ACL). Les mélanger embrouille les clients et les opérateurs.

5) Pourquoi l’activation de HTTP/2 a‑t‑elle changé le comportement de ma limitation ?

HTTP/2 permet de nombreuses requêtes parallèles sur une seule connexion. Si vous vous appuyiez sur le nombre de connexions comme proxy de charge, HTTP/2 casse ce modèle. Limitez par identité/requête à la place.

6) Un WAF peut‑il arrêter le credential stuffing ?

Pas de manière fiable par lui‑même. Le credential stuffing ressemble à du trafic de login normal. Vous avez besoin de limitation de débit, de contrôles par compte, de détection de bots, et idéalement de MFA/score de risque.

7) Comment savoir si mon WAF cause de la latence ?

Regardez le CPU du proxy, le temps de traitement des requêtes, et si la latence augmente alors que le temps upstream reste stable. Les logs d’audit WAF et les champs de timing du proxy aident à corréler.

8) Quelle est la manière la plus sûre d’ajouter des exceptions pour des faux positifs ?

Cadrez‑les étroitement : par route, méthode et nom de paramètre ; gardez l’exception aussi petite que possible ; ajoutez un propriétaire et une date de revue.

9) Dois‑je bloquer par user‑agent ?

Comme signal, oui ; comme identité unique, non. Les user‑agents sont trivials à usurper. Mais des UA vides ou manifestement scriptés peuvent justifier des limites plus strictes ou des challenges.

10) Comment empêcher les attaquants d’usurper l’IP client via X-Forwarded-For ?

Faites confiance aux en‑têtes forwardés seulement depuis des plages d’IP proxy connues. Supprimez les en‑têtes forwardés entrants à l’edge public et définissez vos propres en‑têtes canoniques.

Conclusion : prochaines étapes qui réduisent réellement le bruit des pagers

Si vous ne retenez qu’une chose : les limitations de débit et les WAF sont des fonctionnalités de production. Ils nécessitent observabilité, déploiement par étapes, et tuning continu, comme les bases de données et les pipelines de déploiement.

Faites ces étapes ensuite, dans l’ordre :

  1. Assurez‑vous que seul le proxy edge est exposé à Internet. Pas de ports contournés.
  2. Corrigez la gestion de la véritable IP client et les frontières de confiance des en‑têtes forwardés.
  3. Implémentez des limites par endpoint avec rafales et 429 + Retry-After.
  4. Exécutez le WAF en detection‑only, affinez via les logs, puis appliquez progressivement.
  5. Ajoutez des limites basées sur l’identité après authentification ; arrêtez de compter sur l’IP comme « utilisateur ».
  6. Gardez un kill switch et un seuil de rollback. Votre vous futur vous enverra une note de remerciement.

Le but n’est pas « bloquer les attaquants ». C’est du marketing. Le véritable objectif est : garder le service sain tout en permettant aux utilisateurs légitimes d’effectuer des opérations normales. Le reste, c’est du tuning et de l’humilité.

← Précédent
Imprimantes entre bureaux : Résoudre « Je le vois mais ça n’imprime pas » sur VPN
Suivant →
Avant NVIDIA : ce que « graphismes » signifiait quand la 3D était un luxe

Laisser un commentaire