Table des matières
StupidAntibot
De nos jours les bots sont de véritables plaies pour les webmasters. Les bots des moteurs de recherche et surtout ceux des boîtes d'IA viennent sans relâche marteler votre serveur, parfois au point de le faire tomber.
Les solutions existantes
Il est donc intéressant de lutter contre ces bots pour améliorer la santé de votre serveur. Il existe plusieurs manières de contrer les bots:
- Le
robots.txtest désormais parfaitement inutile puisque plus aucun bot ne les respecte (surtout pas les boîtes d'IA). - Regarder le
User-Agentest inutile : Les boîtes d'IA mentent sur le User-Agent. crowdsecn'a pas vraiment pour but de bloquer les bots, mais plutôt les attaques.- Bloquer des plages d'IP (par exemple tout l'AS de Google ou Facebook) ne sert plus à rien: Les boîtes d'IA passent par d'autres IP (IP résidentielles, smartphones…)
- Bloquer sélectivement des adresses IP ne sert plus à rien non plus puisque les sociétés d'IA passent par des IP résidentielles (PC domestiques et smartphones comme proxy). Votre site reçoit donc des requêtes de dizaines de milliers d'adresses IP différentes. Bloquer chacune de ces IP est vain. (Sans compter que du coup vous risquez de bloquer des utilisateurs légitimes.)
- Des liens invisibles dans vos pages, et vous bloquez les IP qui touchent à ces liens ? Vous risquez de bloquer des internautes légitimes à cause du pré-fetch des navigateurs (qui vont chercher des URLs de la page avant que l'internaute n'ait cliqué quoi que ce soit).
- CloudFlare possède bien sûr une protection antibots, mais au prix de donner à une boîte américaine la totalité du trafic de votre site web, en clair. (Ce que je trouve totalement irrespectueux envers les visiteurs. En plus d'être illégale en Europe (violation du RGPD)).
- Iocaine est tentant pour pourrir les données des IAs, mais cela va augmenter la charge de votre serveur. Ce n'est pas ce qu'on veut ici.
- Anubis est bien entendu un classique (expliqué ici même), mais c'est la solution thermonucléaire. De plus, Anubis étant très répandu, il devient une cible (il semble que certaines boîtes d'IA aient déjà commencé à essayer de le contourner).
Ce qui ralentit votre serveur
Ce qui plombe les sites, ce n'est généralement pas les fichiers statiques servis par le serveur web (il est très performant pour ce genre de tâche), mais plutôt ce qui déclenche des traitements côté serveur (php, java, perl, python…).
Typiquement:
- Avec un wiki, les bots vont récupérer les pages, mais aussi les pages d'historique, la totalité des diffs et éditions, se balader dans les gestionnaires de médias…
- À titre d'exemple, les bots en sont à utiliser le moteur de recherche du gestionnaire de médias de mon DokuWiki (!)
- Si vous avez une forge logicielle, les bots vont parcourir tous les commits, déclencher des calculs de diffs entre commits, parcourir tous les utilisateurs, tous les projets…
- Si votre site a champ "Recherche" les bots vont tenter des recherches avec plein de termes différents.
- Et les bots sont assez stupides pour demander 200 fois par heure la même URL. 🙄
On va donc ici essayer de protéger sélectivement certaines pages pour réduire la charge.
Ce que font les bots
Les bots se contentent généralement:
- de faire une requête http(s) pour récupérer une page
- de parser la page pour extraire le contenu ainsi que toutes les URLs
- d'aller récupérer chacune de ces URLs.
Ce qu'ils ne font généralement pas:
- Ils ne "cliquent" pas dans les pages.
- Ils n'interprètent généralement pas le javascript.
- Ils ne gèrent pas les cookies.
Programmer un bot qui interprète javascript est beaucoup plus lourd, c'est pourquoi les bots ne le font généralement pas. (C'est d'ailleurs sur cela que compte Anubis.)
On va donc utiliser un petit bout de javascript et un cookie. Vous allez voir, c'est bête à manger du foin 🤷♂️, mais cela semble remarquablement efficace contre les bots.
Mise en place
Dans mon .htaccess (Apache2) je mets en place quelques RewriteRules pour faire une redirection sélective sur certaines pages que je veux protéger:
RewriteEngine On
RewriteBase /
# Mon DokuWiki:
RewriteCond %{HTTP_COOKIE} !petitcookie=miam [NC]
RewriteCond %{REQUEST_URI} "^(/wiki.*)$"
RewriteRule ^(.*)$ "/antibot/index.html" [L,QSA,E=antibot:true]
# Mon ancien blog (contient un moteur de recherche)
RewriteCond %{HTTP_COOKIE} !petitcookie=miam [NC]
RewriteCond %{REQUEST_URI} "^(/rhaa.*)$"
RewriteRule ^(.*)$ "/antibot/index.html" [L,QSA,E=antibot:true]
# Ma galerie (certaines URLs provoquent des calculs de miniatures)
RewriteCond %{HTTP_COOKIE} !petitcookie=miam [NC]
RewriteCond %{REQUEST_URI} "^(/galerie.*)$"
RewriteRule ^(.*)$ "/antibot/index.html" [L,QSA,E=antibot:true]
# Mon Shaarli (sauf les liens RSS)
RewriteCond %{HTTP_COOKIE} !petitcookie=miam [NC]
RewriteCond %{REQUEST_URI} "^(/links.*)$"
RewriteCond %{QUERY_STRING} !do=atom [NC]
RewriteCond %{QUERY_STRING} !do=rss [NC]
RewriteRule ^(.*)$ "/antibot/index.html" [L,QSA,E=antibot:true]
Vous remarquerez que dans les URLs de mon Shaarli (/links) je laisse quand même passer les requêtes qui demandent le flux RSS (do=rss ou do=atom) afin que les lecteurs RSS puissent continuer à fonctionner.
Donc si un client essaie d'atteindre une de ces URLs sans avoir le cookie petitcookie=miam j'affiche une page différente (/antibot/index.html).
Un équivalent nginx pour protéger par exemple tout les php:
location ~ [^/]\.php(/|$) {
if ($http_cookie !~* "petitcookie=miam") {
rewrite ^ /antibot/index.html last;
}
}
Voici la page /antibot/index.html en question:
<!DOCTYPE html> <html lang="fr"> <head><title>sebsauvage.net</title><meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.O"> <script> function setMiam(){ const expdate=new Date(); expdate.setTime(expdate.getTime()+(7*24*60*60*1000)); expires="; expires="+expdate.toUTCString(); document.cookie="petitcookie=miam"+expires+"; path=/"; } </script> <style> body{font-size:1.5em;font-family:sans-serif;} button{font-size:1em;} </style> </head> <body onload="document.getElementById('btn').click();"> Bonjour. Mon site étant actuellement bombardé par les boîtes d'IA, je vais devoir vous demander de cliquer ce bouton pour continuer: <button id="btn" onclick="setMiam(); location.reload();">Entrer</button> (Javascript et cookies doivent être activés, désolé.) </body></html>
Que fait cette page:
- Elle affiche un petit message, pose un cookie (valable 7 jours) et recharge la page (Si l'utilisateur n'avait pas Javascript activé, cela lui permet de comprendre qu'il faut l'activer et cliquer sur le bouton).
C'est tout. L'internaute accède alors normalement à la page, et on ne l'embête plus pendant une semaine avec ça.
Ouais, c'est très très con, hein ? Et ça marche ?
Oh oui, ça marche ! 😈 Je vous assure, c'est choquant de voir la quantité de saloperies que ça bloque. Mon serveur souffle enfin.
Pourquoi c'est efficace pour réduire la charge:
- Parce que les bots ne vont pas interpréter le javascript et ne cliqueront pas sur le bouton. Ils ne vont jamais créer le cookie, donc ils ne passeront pas.
- Parce que cette page html ne contient aucune URLs qu'ils puissent parser (on fait juste un
location.reload()) - Parce que cette page est un fichier statique ultra-léger à servir, et que rien d'autre (php,etc.) n'est exécuté côté serveur.
- Comme on ne met pas d'images, de javascript ou de css, il ne génère pas de requêtes supplémentaires sur le serveur.
- Parce que pour Apache gérer une RewriteRule c'est relativement léger.
Alors bien sûr il est évident que c'est trivial à contourner et cela ne vous protègera pas contre une attaque spécialement ciblée pour votre site.
Mais devinez quoi : À moins d'être un très gros poisson (Reddit, StackOverflow, Wikipedia…) aucune boîte d'IA n'ira se donner la peine d'écrire un bout de code pour s'adapter à votre site. Et sentez-vous libre de faire des variations de ce code.
Vous verrez: C'est remarquablement efficace pour dégager les bots. D'ailleurs si vous souhaitez voir les requêtes bloquées, vous pouvez ajouter dans votre configuration Apache:
CustomLog /var/log/apache2/antibot.log common env=antibot
Cela ne va écrire une ligne dans ce log que si la variable antibot est présente (d'où le E=antibot:true dans la RewriteRule). Vous verrez donc une ligne pour chaque requête bloquée.
Effets secondaires
Alors bien sûr cela va aussi bloquer les bots indexeurs des moteurs de recherche, mais de toute manière Google n'est déjà plus capable d'afficher des résultats pertinents et il n'amène plus de trafic.
Mon crédo: Écrire pour les humains, pas pour les robots. Donc je m'en fous totalement que tous les robots soient bloqués.
Si cela vous gêne, vous pouvez affiner les RewriteRules pour ne cibler que les URLs qui consomment trop de ressource (par exemple la recherche fulltext de votre Wiki ou site). Vous pouvez également écrire des RewriteRules pour laisser passer spécifiquement certains robots (Les robots indexeurs des moteurs de recherche ont généralement un User-Agent bien identifié. Ceci dit, c'est tendancieux: Les robots de indexeurs de Google servent aussi pour l'IA. À vous de tester et laisser passer les robots qui se comportent bien.)
License
J'aurais honte de poser une license restrictive sur un truc aussi trivial. Ce bricolage est en licence CC0 (Creative Commons Zero).