Aller au contenu

abuse-guard: Auto-bannir les clients abusifs par taux de réponse d'erreur

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

Installation

Vous pouvez installer ce module sur n'importe quelle 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 v2.0.0 publié le 19 juillet 2026.


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

Chaque scanner, fuzzer et bot de remplissage de credentials laisse la même empreinte : une pluie de 404 à la recherche de chemins cachés, des 403 frappant des portes verrouillées, des requêtes échouées après des requêtes échouées. 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 exclut — décidé à l'intérieur du worker NGINX, sur la requête 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 — un bannissement strict 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 d'un botnet
Mode flotte Réplication de bannissement optionnelle entre les nœuds via Redis / Valkey
Durabilité Instantanés de sortie optionnels préservent les bans actifs entre les 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 résout

Les visiteurs légitimes ne génèrent presque jamais une rafale d'erreurs. Les abus génèrent peu 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 requêtes 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 — un vrai bannissement limité dans le temps — 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 un bannissement est décidé

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

1 · Un score fuyant, 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 continuement à threshold ÷ interval par seconde. Une courte rafale le pousse au-delà de la limite ; un lent filet ne le fait jamais. De manière cruciale, 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 franchit votre seuil, le client gagne un horodatage blocked_until. Jusqu'à ce moment, il est simplement parti — chaque requête est rejetée à la phase de préaccès, avant que NGINX ne consacre un cycle au routage, aux fichiers ou aux upstreams. Le rejet est le résultat le moins coûteux possible.

3 · Un refus correct en matière de confidentialité. Les clients bannis 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 intégré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 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;      # appliquer ici
        }
    }
}
sudo nginx -t && sudo systemctl reload nginx

Ces valeurs par défaut bannissent 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 se compose de quatre directives. La première déclare une politique ; les autres l'appliquent, exemptent des personnes de celle-ci, et (optionnellement) la partagent entre les machines.

Déclarez une politique — abuse_guard_zone

Une directive de niveau http. Elle délimite une zone de mémoire partagée et définit 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 montré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  bannir
                  block=60m;                   combien de temps le bannissement 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 environ une centaine de milliers de 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'IP source. Une requête 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 décroît (valeur par défaut 300s). Une rafale à l'intérieur déclenche un bannissement ; 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 exclu (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 bans de cette zone entre une flotte (voir ci-dessous); off par défaut.
  • persist — un chemin de fichier où les bans actifs sont enregistrés lors de la sortie propre du worker et chargés au démarrage.
  • persist_secret — sur les builds avec support de snapshot signé, une clé hexadécimale qui ajoute une authentification HMAC-SHA256 afin qu'un fichier altéré soit rejeté.

Pourquoi 5xx est laissé de côté par défaut : une erreur serveur est généralement le fait de votre côté, et le compter permettrait à un backend instable 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-la — abuse_guard

Valide dans les blocs http, server et location, donc vous pouvez protéger un site entier 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 banni reçoit, n'importe où dans 400599 (valeur par défaut 429).
  • dry_runon pour observer sans appliquer : le verdict est enregistré mais aucun bannissement n'est écrit. Désactivé par défaut.
  • log_level — à quel niveau chaque décision est enregistrée : info, notice (valeur par défaut), warn, ou error.

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

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 bannis. 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 de recherche vérifiés : autorisez les plages publiées de Googlebot / Bingbot pour qu'un bot parcourant des URL obsolètes (et accumulant des 404) ne soit jamais pris.

Partagez les bans 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 un bannissement obtenu 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 en mode 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 rien en silence tandis que l'application locale continue normalement.

Un bannissement, chaque nœud — sans ralentir une seule requête

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

Chaque nœud décide localement et compte localement. L'instant où il émet un bannissement, 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 requête d'un visiteur n'attend jamais un aller-retour réseau — le seul coût du clustering est qu'un attaquant fraîchement banni est exclu à l'échelle de la flotte une battement plus tard au lieu d'instantanément.

Redis ici est une cloche d'alarme unidirectionnelle, pas un grand livre partagé consulté par requête — 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 y écrire peut émettre des bans.

Bans qui survivent à un redémarrage

Pointez une zone vers un fichier et les bans actifs sont enregistrés lorsque le worker sort proprement, puis restaurés au démarrage. Les rechargements et redémarrages ordonnés conservent les bans actuels sans exécuter un écrivain de zone complet périodique. Une défaillance abrupte de processus ou de machine peut perdre les bans émis depuis la dernière sortie propre ; l'application échoue toujours en mode ouvert.

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

L'instantané compact contient uniquement des digests d'identité et des délais de bannissement. CRC32 détecte la corruption, et un renommage atomique garde les écritures partielles hors du chemin actif. Les builds avec support de snapshot signé peuvent en outre l'authentifier avec persist_secret. Gardez le répertoire lisible uniquement par l'utilisateur worker.

Voir 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 à laquelle le bannissement prend fin, ou 0.
log_format guard '$remote_addr "$request" $status '
                 'guard=$abuse_guard_status count=$abuse_guard_count';

Vous basez-vous 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 requête ? Toute requête dont la key se résout à 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 intacts.

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 d'AddressSanitizer, UndefinedBehaviorSanitizer, Valgrind, analyse statique, et fuzzing continu de ses parseurs et de son format sur disque. Ses dépendances optionnelles — clustering et snapshots signés — sont conçues pour être des efforts de bonne foi : si Redis ou le disque se comportent mal, l'application continue tranquillement à 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.