Aller au contenu

abuse-guard: Auto-interdiction des clients abusifs par taux de réponse d'erreur (404/403/5xx)

Nécessite le plan Pro (ou supérieur) de l'abonnement GetPageSpeed NGINX Extras.

Installation

Vous pouvez installer ce module dans toute distribution basée sur RHEL, y compris, mais sans s'y limiter :

  • RedHat Enterprise Linux 7, 8, 9 et 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 et Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-abuse-guard
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-abuse-guard

Activez le module en ajoutant ce qui suit en haut de /etc/nginx/nginx.conf :

load_module modules/ngx_http_abuse_guard_module.so;

Ce document décrit nginx-module-abuse-guard v1.1.0 publié le 09 juillet 2026.


Votre journal d'erreurs est une confession. Abuse Guard le lit en temps réel et exclut les abuseurs.

Chaque scanner, fuzzer et bot de remplissage de credentials laisse la même empreinte : un spray de 404 à la recherche de chemins cachés, des 403 frappant des portes verrouillées, demande échouée après demande échouée. Abuse Guard surveille les codes d'état que votre serveur retourne réellement, identifie les clients dont le trafic est principalement constitué d'échecs, et les verrouille — décidé à l'intérieur du worker NGINX, sur la demande elle-même, en quelques microsecondes. Pas de sidecar. Pas de log shipper. Pas de couche de script. Juste du C compilé faisant un travail exceptionnellement bien.

Fiche technique

Déclencheur Taux de réponses d'erreur par client que vous choisissez (403/404 par défaut)
Action Verrouillage temporaire — une interdiction stricte pour une fenêtre fixe, pas un ralentissement
Point de décision Phase de préaccès NGINX, avant que tout gestionnaire ou upstream ne s'exécute
Modèle de mémoire Octets fixes par client, indépendants du seuil → à l'échelle des botnets
Mode flotte Réplication d'interdiction optionnelle entre les nœuds via Redis / Valkey
Durabilité Instantanés d'interdiction sur disque optionnels qui survivent aux rechargements et redémarrages
Empreinte Un module autonome ; aucune dépendance d'exécution par défaut
Plateformes RHEL / AlmaLinux / Rocky / CentOS Stream / Oracle / Amazon Linux
##

Le problème qu'il élimine

Les visiteurs légitimes ne génèrent presque jamais une rafale d'erreurs. Les abuseurs ne génèrent guère d'autre chose — cette asymétrie est tout le jeu. Un scanner de vulnérabilités parcourant votre arbre est un mur de 404. Un bot fouillant les points de terminaison administratifs est un mur de 403. Un essai de force brute est un mur d'échecs.

Les limiteurs de taux traitent ce trafic comme n'importe quel autre : ils ralentissent tout le monde par volume de demandes et laissent l'infracteur revenir dès que cela se relâche. Abuse Guard fait le contraire. Il ignore complètement le trafic bien comporté et réserve sa seule réponse — une véritable interdiction à durée limitée — pour les clients définis par leurs erreurs.

Utilisez un limiteur de taux pour façonner la charge. Utilisez Abuse Guard pour évincer les abus.

Comment une interdiction est décidée

Trois éléments en mouvement, tous à l'intérieur du worker :

1 · Un score qui fuit, par client. Chaque identité de client porte un petit nombre dans la mémoire partagée. Chaque erreur correspondante y ajoute ; le score s'épuise continuellement à seuil ÷ intervalle par seconde. Une courte rafale le pousse au-delà de la limite ; un lent filet ne le fait jamais. Crucialement, ce score est un enregistrement de taille fixe peu importe à quel point vous définissez le seuil — donc une seule zone suit confortablement les dizaines de milliers d'adresses sources distinctes qu'un botnet vous lance.

2 · Une date limite stricte. Au moment où le score dépasse votre seuil, le client obtient un horodatage blocked_until. Jusqu'à ce moment, il est simplement absent — chaque demande est rejetée à la phase de préaccès, avant que NGINX ne consacre un cycle à l'acheminement, aux fichiers ou aux upstreams. Le rejet est le résultat le moins coûteux possible.

3 · Un refus conforme à la vie privée. Les clients interdits reçoivent 429 Too Many Requests (votre choix de code) étiqueté de sorte qu'aucun cache partagé ne puisse jamais le stocker et servir la punition d'un client à un autre, avec un Retry-After indiquant aux clients honnêtes quand revenir.

Les identités sont repliées dans un digest de taille fixe, donc se baser sur quelque chose de volumineux comme $request_uri ou un en-tête coûte exactement autant de mémoire que de se baser sur une adresse IP.

En direct en moins d'une minute

Abuse Guard est livré en tant que module précompilé et signé depuis le dépôt GetPageSpeed — déposez-le, aucun outil de construction requis.

sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install nginx-module-abuse-guard

Connectez-le :

load_module modules/ngx_http_abuse_guard_module.so;

http {
    abuse_guard_zone zone=clients:10m;     # une zone de mémoire partagée

    server {
        location / {
            abuse_guard zone=clients;      # appliquez ici
        }
    }
}
sudo nginx -t && sudo systemctl reload nginx

Ces valeurs par défaut interdisent toute IP qui retourne 100 403/404 réponses dans une fenêtre de 5 minutes, pendant une heure. Resserrez ou assouplissez chaque nombre ci-dessous.

Configuration

Abuse Guard est constitué de quatre directives. La première déclare une politique ; les autres l'appliquent, exemptent des personnes et (optionnellement) la partagent entre les machines.

Déclarez une politique — abuse_guard_zone

Une directive au niveau http. Elle définit une zone de mémoire partagée et établit la politique qui la régit. Définissez autant ou aussi peu de paramètres que vous le souhaitez — le nom et la taille de la zone sont les seules choses que vous devez fournir ; des valeurs par défaut sensées remplissent le reste (les valeurs indiquées ci-dessous sont exactement ces valeurs par défaut).

abuse_guard_zone  zone=clients:10m             nom + taille (le seul indispensable)
                  key=$binary_remote_addr      qui est "un client"
                  statuses=403,404             quelles réponses comptent comme erreurs
                  interval=300s                la fenêtre de notation
                  threshold=100                erreurs dans cette fenêtre  interdiction
                  block=60m;                   combien de temps l'interdiction dure

zone=clients:10m est l'identité et le budget de la politique : un nom que vous référencez depuis abuse_guard, et la taille de la mémoire partagée. Environ 10 Mo suivent de l'ordre de cent mille clients actifs.

Tout le reste est un réglage optionnel :

  • key — l'expression qui définit un seul client. N'importe quelle variable NGINX ; la valeur par défaut $binary_remote_addr se base sur l'adresse IP source. Une demande dont la clé est vide est complètement ignorée (pratique avec un map, ci-dessous).
  • statuses — les codes de réponse qui comptent comme erreurs : codes individuels, plages, ou un mélange, par exemple statuses=401,403,404,500-599. Par défaut 403,404.
  • interval — la fenêtre sur laquelle le score s'épuise (valeur par défaut 300s). Une rafale à l'intérieur déclenche une interdiction ; un lent filet étalé ne s'accumule jamais.
  • threshold — combien d'erreurs dans cette fenêtre franchissent la limite, jusqu'à 1024 (valeur par défaut 100).
  • block — combien de temps un client déclenché reste verrouillé (valeur par défaut 60m).
  • inactive — combien de temps un client dormant reste en mémoire avant d'être récupéré (valeur par défaut max(1h, interval, block) ; toute valeur explicite doit être au moins aussi grande que interval et block).
  • redison pour répliquer les interdictions de cette zone entre une flotte (voir ci-dessous); off par défaut.
  • persist — un chemin de fichier pour enregistrer les interdictions afin qu'elles survivent à un redémarrage.
  • persist_interval — à quelle fréquence cet instantané est réécrit (valeur par défaut 5s).
  • persist_secret — une clé hexadécimale qui signe l'instantané avec HMAC-SHA256, de sorte qu'un fichier falsifié soit rejeté plutôt que chargé.

Pourquoi 5xx est laissé de côté par défaut : une erreur serveur est généralement de votre côté, et le compter permettrait à un backend défaillant de faire bannir des visiteurs innocents. Ajoutez statuses=403,404,500-599 uniquement lorsque vous souhaitez délibérément agir sur les clients qui déclenchent des erreurs serveur.

Appliquez-le — abuse_guard

Valide dans les blocs http, server et location, vous pouvez donc protéger tout un site ou juste les points de terminaison qui attirent les abus. Nommez la zone pour l'activer ; écrivez abuse_guard off; dans un scope imbriqué pour la désactiver.

location /wp-login.php {
    abuse_guard zone=clients status=429 log_level=warn;
}
  • zone — la zone (déclarée ci-dessus) dont la politique s'applique ici.
  • status — le code qu'un client interdit reçoit, n'importe où dans 400599 (valeur par défaut 429).
  • dry_runon pour observer sans appliquer : le verdict est enregistré mais aucune interdiction n'est écrite. Désactivé par défaut.
  • log_level — à quel niveau enregistrer chaque décision : info, notice (valeur par défaut), warn, ou error.

Déployez sans crainte avec dry_run=on. Cela enregistre chaque interdiction qu'il ferait émettre sans toucher à l'état, afin que vous puissiez calibrer les seuils par rapport au trafic en direct — même à côté d'un emplacement appliquant des règles sur la même zone — puis le passer en direct.

Exemptez les bons gars — abuse_guard_allow

Contexte : http · server · location · répétable, hérité vers le bas.

abuse_guard_allow 127.0.0.0/8;
abuse_guard_allow 10.0.0.0/8 192.168.0.0/16;

Les clients listés ne sont jamais comptés et jamais interdits. La correspondance se fait sur la véritable adresse de connexion, donc cela coopère avec realip. C'est aussi ainsi que vous protégez les robots d'exploration vérifiés : autorisez les plages publiées de Googlebot / Bingbot afin qu'un bot parcourant des URL obsolètes (et accumulant des 404) ne soit jamais attrapé.

Partagez les interdictions entre la flotte — abuse_guard_redis

Contexte : http

abuse_guard_redis host=10.0.0.5 password=… ;   # tls://host pour TLS
abuse_guard_zone  zone=clients:10m redis=on;

Pointez chaque nœud vers un Redis ou Valkey, activez redis=on, et une interdiction gagnée sur n'importe quelle machine se propage à toutes. Valeurs par défaut : port=6379, db=0, prefix=ag_, timeout=100ms. Comment cela reste rapide est la section suivante.

SELinux : sur les systèmes d'application (RHEL, Rocky, AlmaLinux), le noyau empêche NGINX d'ouvrir la connexion à Redis jusqu'à ce que vous le permettiez une fois — setsebool -P httpd_can_network_connect 1. Ignorez cela et la réplication ne fait silencieusement rien pendant que l'application locale continue normalement.

Une interdiction, chaque nœud — sans ralentir une seule demande

Derrière un équilibreur de charge, une interdiction par serveur est du théâtre : l'attaquant atterrit simplement sur un autre nœud. Abuse Guard comble cette lacune sans jamais mettre Redis dans le chemin de la demande.

Chaque nœud décide localement et compte localement. L'instant où il émet une interdiction, il diffuse ce fait au cluster et enregistre une copie durable. Chaque autre nœud l'importe en quelques millisecondes, et tout nœud qui était hors ligne se réconcilie au moment où il se reconnecte. Parce que l'application est toujours servie à partir de l'état en mémoire de chaque nœud, la demande d'un visiteur n'attend jamais un aller-retour réseau — le seul coût de la mise en cluster est qu'un attaquant fraîchement banni est exclu de la flotte un battement plus tard au lieu d'immédiatement.

Redis ici est une cloche d'alarme unidirectionnelle, pas un grand livre partagé consulté par demande — donc un Redis lent ou manquant ne peut jamais ajouter de latence à votre trafic. Exécutez-le sur un réseau privé et traitez-le comme privilégié : tout ce qui peut écrire dessus peut émettre des interdictions.

Interdictions qui survivent à un redémarrage

Pointez une zone vers un fichier et les interdictions actives sont instantanées à intervalles réguliers et restaurées au démarrage, de sorte qu'un rechargement ou un redémarrage ne donne pas à chaque attaquant une ardoise fraîche.

abuse_guard_zone zone=clients:10m
                 persist=/var/lib/nginx/abuse_guard/clients.state
                 persist_secret=00112233445566778899aabbccddeeff;

L'instantané est vérifié pour son intégrité, écrit de sorte qu'un crash ne puisse jamais laisser un fichier déchiré, et — avec persist_secret — signé cryptographiquement afin qu'un fichier falsifié soit rejeté plutôt que de faire confiance. Gardez le répertoire lisible uniquement par l'utilisateur worker.

Voyez tout ce qu'il décide

Trois variables exposent le verdict d'Abuse Guard à vos journaux et à votre configuration :

Variable Valeur
$abuse_guard_status BYPASSED · PASSED · COUNTED · BLOCKED · DRY_RUN
$abuse_guard_count Erreurs actuellement attribuées à ce client.
$abuse_guard_blocked_until Temps Unix auquel l'interdiction se lève, ou 0.
log_format guard '$remote_addr "$request" $status '
                 'guard=$abuse_guard_status count=$abuse_guard_count';

Clé derrière un CDN ou un proxy ? Ne faites jamais confiance à un X-Forwarded-For brut. Laissez realip résoudre le véritable client d'abord, puis basez-vous sur $binary_remote_addr :

set_real_ip_from 10.0.0.0/8;
real_ip_header   X-Forwarded-For;
real_ip_recursive on;

Besoin d'une logique d'exemption par demande ? Toute demande dont la key se résout en une chaîne vide est ignorée — donc un map vous permet, par exemple, de suivre les visiteurs anonymes par IP tout en laissant les utilisateurs authentifiés intouchés.

Conçu pour être fiable en production

Abuse Guard est soumis à une norme bien au-dessus de "cela compile." Chaque changement passe par le parcours de AddressSanitizer, UndefinedBehaviorSanitizer, Valgrind, analyse statique, et fuzzing continu de ses parseurs et de son format sur disque. Ses dépendances optionnelles — mise en cluster et instantanés signés — sont conçues pour un effort maximal : si Redis ou le disque se comportent mal, l'application continue silencieusement à partir de la mémoire locale. Votre trafic n'est jamais pris en otage par une dépendance.

Obtenez Abuse Guard

Abuse Guard est un module NGINX commercial de GetPageSpeed LLC, livré avec des mises à jour et un support continus via un abonnement GetPageSpeed.

© GetPageSpeed LLC. Tous droits réservés.