Sur la carte des attaques, une tache dense recouvre un pays, et la règle «interdire ce pays en entier» vient d’elle-même. Elle n’apportera presque rien : changer de pays de sortie coûte quelques minutes à l’attaquant, alors que le blocage touchera vos propres visiteurs et vous-même en déplacement. Pire, un robot visible venu d’un seul nuage déménagera sur des adresses résidentielles après le blocage et deviendra indiscernable des humains.
Voici cinq étapes qui, sur ce même serveur, donnent un résultat : couper les scanners, limiter la cadence, ne pas couper ce qui est nécessaire et, si cela s’avère tout de même nécessaire, bloquer correctement. Tout cela se vérifie et se configure en une seule séance.
Étape 1. Regarder qui crée réellement la tache
Trouvez d’abord le journal des requêtes. Sur un serveur hébergeant plusieurs sites, access.log est souvent vide, tandis que les entrées vont dans le journal de l’hôte virtuel concerné :
sudo ls -lS /var/log/apache2/*access*.log /var/log/apache2/*requests*.log 2>/dev/null
Dans toutes les commandes qui suivent, remplacez le chemin par le fichier arrivé en tête de cette liste. D’abord les adresses en tête sur la journée, puis ce que demande exactement celle qui est en haut :
sudo awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20
sudo grep '^203\.0\.113\.' /var/log/apache2/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
La seconde commande répond à la question principale. Si la sortie contient des dizaines de pages différentes de votre site, c’est un collecteur de contenu : il est inoffensif et il suffit de ne pas le compter comme visiteur. Si l’on y trouve /wp-login.php, /.env, /phpmyadmin et d’autres choses que vous n’avez pas, c’est un scanner, et l’étape 2 s’en occupe. Pour nginx, les journaux se trouvent dans /var/log/nginx/, les champs sont les mêmes.
Étape 2. Une prison pour les requêtes vers ce que vous n’avez pas
Le chemin demandé ne peut pas être falsifié — il est l’intention même, contrairement à l’adresse et au User-Agent. Le filtre /etc/fail2ban/filter.d/web-probes.local :
[Definition]
failregex = ^<HOST> .* "(GET|POST|HEAD) /(wp-login\.php|wp-admin|xmlrpc\.php|\.env|\.git/|phpmyadmin|administrator/)
ignoreregex =
La prison /etc/fail2ban/jail.d/web-probes.local :
[web-probes]
enabled = true
port = http,https
filter = web-probes
logpath = /var/log/apache2/*access.log
maxretry = 1
findtime = 1h
bantime = 1d
Ici, maxretry = 1 est justifié : on ne tombe pas par hasard sur l’interface d’administration d’autrui. Appliquer et s’assurer que le filtre attrape bien des lignes dans votre journal :
sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/web-probes.local
sudo systemctl reload fail2ban && sudo fail2ban-client status web-probes
Étape 3. Limiter la cadence
Le scanner et le robot se trahissent par leur vitesse, quel que soit leur pays d’origine. Trente pages par minute depuis une seule adresse, c’est un seuil qui n’atteint pas une personne en train de parcourir un catalogue :
[http-flood]
enabled = true
port = http,https
filter = apache-overflows
logpath = /var/log/apache2/site_access.log
maxretry = 30
findtime = 60
bantime = 1h
Le détail décisif est le journal indiqué dans logpath. Si le motif englobe le journal du panneau de gestion lui-même ou celui de l’administration, vous allez vous bannir vous-même : une seule de ses pages entraîne une dizaine de requêtes vers les styles et les scripts, et trente sont atteintes en deux clics. C’est pourquoi on donne au panneau son propre fichier de journal, qui ne correspond pas au motif de la prison, et aux fichiers statiques une longue durée de mise en cache, pour que le navigateur ne les redemande pas à chaque page. Le symptôme, si cela arrive quand même : le HTML arrive, la mise en forme non, la page reste bloquée. Lever le bannissement :
sudo fail2ban-client set http-flood unbanip 203.0.113.10
Étape 4. Protéger ce qu’il ne faut pas couper
Avant d’activer les blocages, inscrivez les exceptions — sinon ce qui est nécessaire sera touché le premier :
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24 66.249.64.0/19
Ce qui doit impérativement figurer dans cette ligne, et pourquoi :
- Votre propre adresse ou le sous-réseau du bureau. La cause la plus fréquente d’une perte d’accès au serveur est votre propre règle, pas une attaque ;
- La plage
66.249.64.0/19. Le robot de recherche de Google s’identifie par le User-Agent, mais la partie qui exécute le JavaScript arrive sous unChrome/Linuxordinaire et ne se nomme pas. Toute règle du genre «bloquer le trafic des centres de données» atteint précisément celle-là, après quoi les pages disparaissent discrètement de l’index. Une adresse suspecte peut être vérifiée par une requête inverse :dig -x 66.249.66.1 +shortdoit renvoyer un nom dans la zonegooglebot.com; - Les adresses des notifications de paiement. Les webhooks des systèmes de paiement arrivent depuis des serveurs AWS et Azure. Si vous fermez ces nuages en entier, les confirmations de paiement cesseront d’arriver, et vous l’apprendrez le jour où un client écrira que l’argent a été débité mais que l’accès n’est pas là. Les plages se trouvent dans la documentation de votre prestataire de paiement.
Étape 5. Si un blocage est tout de même nécessaire, bloquez un sous-réseau, pas un pays
Un épaississement durable venu d’un seul réseau, qui tient pendant des jours et s’accompagne de requêtes toutes semblables, c’est un exécutant unique qui parcourt une liste. Ce cas se bloque de façon ciblée et pour une durée limitée :
sudo ufw deny from 198.51.100.0/22 to any
sudo ufw status numbered
Avec la seconde commande, notez le numéro de la règle : c’est par lui qu’il faudra lever le blocage, sudo ufw delete <numéro>. Fixez-vous une échéance — un mois, par exemple — et inscrivez la levée dans votre agenda. Les règles posées «pour toujours» se transforment en un an en une liste que personne n’ose toucher, parce que personne ne se souvient pourquoi ces adresses y sont arrivées.
Pour savoir quel sous-réseau bloquer, partez de l’adresse de la première étape : whois 198.51.100.17 | grep -iE 'route|cidr|netname'.
Ce qui change après ces cinq étapes
Les scanners sont coupés selon l’intention et non selon l’origine, et sont attrapés dès la première requête. Les robots butent sur la limite de cadence. Le robot de recherche et les notifications de paiement continuent de passer. Le seul blocage large qui reste est ciblé, avec une échéance connue et une raison claire.
La carte, elle, ne disparaît pas, mais son rôle change : elle ne sert pas à fermer des pays, mais à remarquer l’épaississement lui-même et à le comparer à ce qu’il était la semaine précédente. Pour cela, il faut un historique et non un instantané de la journée en cours. À quoi ressemble une telle carte, à côté du journal des bannissements et de la liste des ports ouverts, les pages de démonstration ci-dessous le montrent.