Vous ne le réalisez peut-être pas, mais votre site Web est constamment menacé. S’il exécute WordPress, des robots essaient de vous spammer. S'il y a une page de connexion, il y a des attaques de mot de passe par force brute. Vous pouvez également considérer les robots des moteurs de recherche comme des visiteurs indésirables.
Protéger votre site contre les activités indésirables, suspectes et malveillantes n’est pas une tâche facile. Les pare-feu d'applications Web, tels que NGINX App Protect et les modules certifiés NGINX Plus disponibles auprès de nos partenaires, sont des outils efficaces et doivent être considérés comme faisant partie de votre pile de sécurité. Pour la plupart des environnements, il n’existe pas de sécurité excessive, et une approche multicouche est invariablement la plus efficace.
Dans cet article de blog, nous discuterons de l'utilisation de fail2ban comme autre couche de la pile de sécurité Web. Fail2ban est un système de détection d'intrusion (IDS) qui surveille en permanence les fichiers journaux pour détecter toute activité suspecte, puis exécute une ou plusieurs actions préconfigurées. En règle générale, fail2ban surveille les tentatives de connexion infructueuses, puis bloque (bannit) l'adresse IP incriminée pendant un certain temps. Il s’agit d’une défense simple mais efficace contre les attaques de mot de passe par force brute.
Dans NGINX Plus R13, nous avons introduit un magasin de clés-valeurs natif et une nouvelle API NGINX Plus. Cela permet une multitude de solutions de configuration dynamique dans lesquelles la configuration et le comportement de NGINX Plus peuvent être pilotés par un système externe. Dans cet article de blog, nous montrerons également comment fail2ban peut être utilisé pour reconfigurer automatiquement NGINX Plus afin d'ignorer les requêtes provenant d'adresses IP qui ont provoqué plusieurs échecs d'authentification.
Éditeur – Dans NGINX Plus R16 et versions ultérieures, les magasins de clés-valeurs peuvent être synchronisés sur toutes les instances NGINX Plus d’un cluster. (Le partage d’état dans un cluster est également disponible pour d’autres fonctionnalités NGINX Plus.) Pour plus de détails, consultez notre blog et le Guide d'administration NGINX Plus .
Le magasin clé-valeur NGINX Plus est un magasin natif en mémoire doté de trois caractéristiques principales :
Le magasin clé-valeur est défini en créant une zone de mémoire partagée nommée par la directive keyval_zone
. Ce magasin de valeurs clés peut ensuite être rempli avec un ensemble initial de valeurs en utilisant la méthode HTTP POST
pour soumettre un objet JSON à l'API. La directive keyval
définit ensuite quelle variable existante sera utilisée comme clé de recherche ( $remote_addr
dans l'exemple) et le nom d'une nouvelle variable ( $num_failures
) qui sera évaluée à partir de la valeur correspondante de cette clé.
L'API est activée en désignant un bloc d'emplacement
comme point de terminaison de l'API NGINX Plus.
server {
listen 1111;
allow 127.0.0.1; # Autoriser uniquement l'accès depuis l'hôte local,
refuser tout ; # et empêcher l'accès à distance.
location /api {
api write=on; # Le point de terminaison de l'API NGINX Plus en mode lecture/écriture
}
}
keyval_zone zone=denylist:1M;
keyval $remote_addr $num_failures zone=denylist;
server {
listen 80;
location / {
root /usr/share/nginx/html;
if ($num_failures) {
return 403;
}
}
}
vim: syntax=nginx
Avant d’y ajouter des paires clé-valeur, une demande de contenu du magasin de listes de refus renvoie un objet JSON vide.
$ curl http://localhost:1111/api/6/http/keyvals/denylist {}
Le magasin clé-valeur peut désormais être rempli avec une paire clé-valeur initiale à l’aide de la méthode HTTP POST
(sous la forme de l’argument -d
de la commande curl
) pour soumettre un nouvel objet JSON. Plusieurs paires clé-valeur peuvent être envoyées par POST
vers un magasin clé-valeur vide et individuellement par la suite.
$ curl -iX POST -d '{"10.0.0.1":"1"}' http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 201 Créé ...
Une paire clé-valeur est supprimée en appliquant un PATCH
à la clé avec une valeur null
.
$ curl -iX PATCH -d '{"10.0.0.1":null}' http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 204 Aucun contenu ...
Toutes les paires clé-valeur peuvent être supprimées du magasin clé-valeur en envoyant la méthode DELETE
.
$ curl -iX DELETE http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 204 Aucun contenu ...
Une implémentation simple de la liste de blocage IP peut désormais être configurée.
server {
listen 1111;
allow 127.0.0.1; # Autoriser uniquement l'accès depuis l'hôte local,
refuser tout ; # et empêcher l'accès à distance.
location /api {
api write=on; # Le point de terminaison de l'API NGINX Plus en mode lecture/écriture
}
}
keyval_zone zone=denylist:1M;
keyval $remote_addr $num_failures zone=denylist;
server {
listen 80;
location / {
root /usr/share/nginx/html;
if ($num_failures) {
return 403;
}
}
}
vim: syntax=nginx
Cet extrait de configuration configure le port 80 comme serveur Web. La ligne 18 évalue la variable $num_failures
sur la partie valeur de la paire clé-valeur dans la zone de mémoire partagée de la liste de refus qui correspond à la clé qui correspond à la variable $remote_addr
(adresse IP du client). Ce processus d'évaluation de $num_failures
est exprimé plus clairement de manière séquentielle :
$remote_addr
au magasin de valeurs-clés de la liste de refus$remote_addr
correspond exactement à une clé, obtenez la valeur de cette paire clé-valeur$num_failures
Et donc, si l'adresse IP du client a été POSTE
-é dans le magasin clé-valeur, toutes les requêtes aboutissent à un HTTP 403
Interdit
erreur. L’avantage de cette approche, par opposition à l’utilisation d’un bloc de carte
dans le même but, est que la liste de refus IP peut être contrôlée par un système externe.
Comme mentionné ci-dessus, fail2ban est couramment utilisé pour détecter une activité suspecte et/ou malveillante dans les fichiers journaux, puis prendre des mesures pour protéger le système. L’action par défaut consiste à configurer iptables
pour supprimer tous les paquets provenant de l’adresse IP enregistrée. Cette approche, bien qu’efficace pour bloquer un acteur malveillant, offre une expérience utilisateur très médiocre aux utilisateurs authentiques, surtout s’ils ont oublié leur mot de passe. Pour ces utilisateurs, il semble que le site Web soit tout simplement indisponible.
La configuration suivante décrit une action fail2ban qui soumet l’adresse IP incriminée au magasin de valeurs-clés de la liste de refus NGINX Plus. NGINX Plus affiche ensuite une page d’erreur plus utile et applique simultanément une limite de taux de requête à cette adresse IP afin que si les actions font partie d’une attaque, l’attaque soit efficacement neutralisée.
Nous supposons une installation par défaut de fail2ban sur le même hôte que NGINX Plus, avec toute la configuration sous le répertoire /etc/fail2ban .
L’action fail2ban suivante utilise l’API NGINX Plus pour ajouter et supprimer des adresses IP « interdites » dans le magasin de clés-valeurs de la liste de refus de la même manière que notre exemple simple ci-dessus. Nous plaçons le fichier nginx-plus-denylist.conf dans le répertoire /etc/fail2ban/action.d .
[Définition]
actionban = curl -s -o /dev/null -d '{"":""}' http://localhost:1111/api/6/http/keyvals/denylist
actionunban = curl -s -o /dev/null -X PATCH -d '{"":null}' http://localhost:1111/api/6/http/keyvals/denylist
La prison fail2ban suivante active le filtre intégré qui détecte les tentatives de connexion infructueuses à l'aide du module d'authentification de base HTTP de NGINX et applique l'action définie dans nginx-plus-denylist.conf . De nombreux autres filtres intégrés sont disponibles et peuvent être facilement créés pour détecter les activités indésirables dans les journaux d’accès NGINX.
[DEFAUT]
bantime = 120
banaction = nginx-plus-denylist
[nginx-http-auth]
activé = true
L’extrait de configuration NGINX Plus suivant applique l’authentification HTTP de base à la page par défaut « Bienvenue sur NGINX ». Nous plaçons le fichier password_site.conf dans le répertoire /etc/nginx/conf.d .
serveur {
écoute 1111 ;
autoriser 127.0.0.1 ; # Autoriser uniquement l'accès depuis l'hôte local,
refuser tout ; # et empêcher l'accès à distance.
emplacement /api {
api write=on ; # Le point de terminaison de l'API NGINX Plus en mode lecture/écriture
}
}
keyval_zone zone=denylist:1M state=denylist.json ;
keyval $remote_addr $num_failures zone=denylist ;
limit_req_zone $binary_remote_addr zone=20permin:10M rate=20r/m ;
serveur {
écoute 80 ;
racine /usr/share/nginx/html ;
emplacement / {
auth_basic "site fermé" ;
auth_basic_user_file users.htpasswd ;
si ($num_failures) {
réécriture ^.* /banned.html ;
}
}
emplacement = /banned.html {
limit_req zone=20permin burst=100;
}
}
vim : syntaxe=nginx
La ligne 11 définit la keyval_zone
comme dans denylist_keyval.conf ci-dessus, mais avec l'ajout du paramètre state
, qui spécifie un fichier dans lequel l'état du magasin clé-valeur est stocké et persiste donc lorsque NGINX Plus est arrêté et redémarré. Le magasin clé-valeur persiste lors des rechargements de configuration réguliers sans spécifier de fichier d’état. (Les lignes 1 à 10 ne sont pas affichées, mais sont les mêmes que dans denylist_keyval.conf .)
La ligne 14 crée une zone de mémoire partagée appelée 20permin et spécifie un taux de demande maximal de 20 demandes par minute pour chaque adresse IP client. Cette limite de débit est ensuite appliquée lorsqu'une adresse IP est ajoutée à la liste de refus par fail2ban (ligne 30).
Le bloc serveur
définit un serveur Web à l'écoute sur le port par défaut (80), où toutes les requêtes correspondent à l' emplacement
/
bloc (ligne 20). La directive racine
(ligne 18) spécifie où réside notre contenu Web. Les lignes 21 à 22 précisent que l'authentification HTTP de base est requise pour ce site et que la base de données des mots de passe des utilisateurs autorisés se trouve dans le fichier users.htpasswd . La documentation de la directive auth_basic_user_file
décrit le format de ce fichier. Notez que cette configuration n'est pas chiffrée à des fins de test et que tout site Web de production utilisant l'authentification HTTP de base doit utiliser SSL/TLS pour la sécurité du transport.
Lorsque l'adresse IP du client a été mise sur liste noire (lignes 24 à 26), au lieu de renvoyer le HTTP403
code d'erreur, nous réécrivons la requête en /banned.html qui est ensuite traitée dans le bloc d'emplacement
qui correspond exactement à cet URI (ligne 29). Cela renvoie une page Web statique qui explique que l'adresse IP de l'utilisateur a été bloquée en raison d'échecs de connexion excessifs. Il applique également une limite de débit restrictive (ligne 30) qui empêche un client malveillant de consommer inutilement des ressources système.
(Le code HTML de cet exemple de page Web est disponible sous le nom forbidden.html dans le référentiel GitHub de cet article.)
Nous pouvons simuler des tentatives de connexion échouées successives et l’activité fail2ban correspondante comme suit.
$ curl -i http://admin:motdepasse@www.exemple.com/HTTP/1.1 401 Non autorisé...
$ curl -i http://admin:admin@www.exemple.com/
HTTP/1.1 401 Non autorisé...
$ curl -i http://admin:pass1234@www.exemple.com/
HTTP/1.1 401 Non autorisé...
$ curl -i http://admin:letmein@www.exemple.com/
HTTP/1.1 401 Non autorisé...
$ curl -i http://admin:fred@www.exemple.com/
HTTP/1.1 401 Non autorisé...
$ boucle http://admin:P@ssw0rd@www.exemple.com/
<!DOCTYPE html>
<html>
<head>
<title>Interdit</titre>
...
$ queue -f /var/log/fail2ban.log
2017-09-15 13:55:18,903 fail2ban.filter [28498] : INFO [nginx-http-auth] Trouvé 172.16.52.1 2017-09-15 13:55:28,836 fail2ban.filter [28498] : INFO [nginx-http-auth] Trouvé 172.16.52.1 2017-09-15 13:57:49,228 fail2ban.filter [28498] : INFO [nginx-http-auth] Trouvé 172.16.52.1 2017-09-15 13:57:50,286 fail2ban.filter [28498] : INFO [nginx-http-auth] Trouvé 172.16.52.1 2017-09-15 13:57:52,015 fail2ban.filter [28498] : INFO [nginx-http-auth] Trouvé 172.16.52.1 2017-09-15 13:57:52,088 fail2ban.actions [28498] : AVIS [nginx-http-auth] Interdiction 172.16.52.1 2017-09-15 13:59:52,379 fail2ban.actions [28498] : AVIS [nginx-http-auth] Annulation de l'interdiction 172.16.52.1
Cette solution de liste de refus d'adresses IP dynamiques peut désormais fonctionner sans aucune modification de configuration supplémentaire. Fail2ban surveille les fichiers journaux NGINX et ajoute les adresses IP interdites au magasin de clés-valeurs NGINX Plus à l'aide de l'API. Après 120 secondes (le délai d'interdiction
configuré dans jail.local ), l'adresse IP incriminée est supprimée de la liste de blocage, à nouveau à l'aide de l'API NGINX Plus, et les tentatives de connexion sont à nouveau acceptées à partir de cette adresse.
L'API NGINX Plus et le magasin clé-valeur rendent ce type d'intégration possible. Des solutions de configuration avancées peuvent désormais être obtenues sans nécessiter la construction de fichiers de configuration NGINX Plus ni effectuer de rechargements. Nous aimerions savoir comment vous utilisez ces fonctionnalités pour créer vos propres solutions de configuration dynamiques. Veuillez ajouter un commentaire ci-dessous.
Pour essayer NGINX Plus, démarrez votre essai gratuit de 30 jours dès aujourd'hui ou contactez-nous pour discuter de vos cas d'utilisation.
« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."