Un fichier censé protéger peut aussi mordre.
Le principe est simple, mais il faut bien le retourner dans le bon sens.
Le problème du Disallow
robots.txt sert à indiquer aux crawlers les chemins à ne pas explorer. Un Googlebot ou un Bingbot respecte la consigne. Un bad bot, lui, fait l'inverse : il lit robots.txt justement pour savoir où chercher, en misant sur le fait qu'un chemin exclu est souvent un chemin sensible.
Ce fichier, censé protéger, devient une liste de cibles pour qui ne respecte pas la règle.
Un exemple
Pas besoin d'aller loin pour trouver le cas d'école. Ce robots.txt généré par un plugin WordPress, croisé lors d'une revue, cumule à peu près toutes les erreurs possibles.
# This virtual robots.txt file was created by the Virtual Robots.txt WordPress plugin
User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
Disallow: /wp-includes/
Allow: /wp-includes/js/
Allow: /wp-includes/images/
Disallow: /trackback/
Disallow: /wp-login.php
Disallow: /wp-register.php
Disallow: */?f*
Disallow: */?agencies=*
Disallow: ?output=
Disallow: /local/gravars.php
User-agent: GPTBot
Disallow: /
Explication
- Le commentaire du plugin, laissé tel quel.
La première ligne annonce direct la stack (WordPress) et le plugin utilisé, avec sa version potentiellement identifiable via le changelog public. Une info de reconnaissance offerte gratuitement. - Des Disallow qui révèlent plus qu'ils ne cachent.
/local/gravars.phpnomme un script précis, probablement un outil interne.*/?agencies=*dévoile l'existence d'une fonctionnalité métier autour des agences. Exactement le travers dont on parlait plus haut : le fichier documente ce qu'il prétend cacher. - Une syntaxe douteuse.
Disallow: ?output=sans/en préfixe ne respecte pas la RFC 9309, qui impose qu'un pattern commence par/ou*. Cette ligne risque d'être tout simplement ignorée par les parsers stricts, donc inefficace tout en révélant quand même le paramètre. - Un blocage IA cosmétique.
GPTBotest bloqué seul, sans toucherGoogle-Extended,CCBot,PerplexityBot,ClaudeBotouanthropic-ai. Soit un choix volontaire resté inachevé, soit un copier-coller d'exemple trouvé quelque part sans recul sur sa portée réelle.
Rien de tout ça n'est un honeypot volontaire. C'est justement le profil de fichier qu'il vaut mieux éviter et qu'on va transformer.
Le principe
L'idée : déclarer un ou plusieurs chemins fictifs, qui n'existent nulle part ailleurs sur le site. Aucun lien HTML ne pointe vers eux, aucun sitemap ne les référence. Seul un bot qui parse robots.txt pour y chercher des cibles ira les demander.
Un humain n'a aucune raison d'y accéder. Un crawler légitime les exclut par définition. Toute requête sur ces chemins est donc un signal quasi certain de comportement malveillant.
User-agent: *
Disallow: /wp-admin-legacy/
Disallow: /db-backup/
Disallow: /old-config/
Crawl-Delay: 10
Allow: /
Pas besoin de multiplier les chemins. Un seul suffit pour détecter, plusieurs permettent d'affiner le profil du scanner selon celui qui mord. Mais mettre des chemins « tentants », c'est plus rigolo.
Interception côté .htaccess
Il n'y a plus qu'à transformer la requête sur ces chemins fictifs en action de blocage. Une RewriteRule placée en tête de bloc, avant toute autre règle de réécriture, intercepte la requête et redirige vers un script dédié.
<IfModule mod_rewrite.c>
RewriteEngine on
# Honeypot robots.txt : chemins fictifs, seuls les scanners qui parsent
# robots.txt pour y chercher des cibles les demanderont
# Au passage, on peut ajouter des blocages de « base », juste histoire de les embrouiller.
RewriteRule ^(config|admin|administrator|login|signin|phpmyadmin|adminer|manager|backup|backup(-2K\d{2})?|wp-admin|wp-login\.php|wp-content|xmlrpc\.php|\.env|\.git|\.svn|\.aws|\.ssh|install|installer|setup|phpinfo|debug|test|vendor|node_modules|tmp|cache)(/.*)?$ /honeypot/ [NC,L]
# Les autres règles après…
</IfModule>
Le flag NC rend le match insensible à la casse (Wp-Admin-Legacy, DB-BACKUP, Old-Config sont interceptés aussi). Le (/.*)? capture les sous-chemins que le bot pourrait tester après la racine du leurre (/db-backup/dump.sql, /old-config/settings.php).
Un script de blocage
<?php
declare(strict_types=1);
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
if ($ip !== '') {
// Intégration avec le système de ban existant (fichier, table, CIDR…)
// à coder, ou ne rien faire…
}
// Ralentit la réponse juste pour faire chi** les scrappers
sleep(10);
ob_start("ob_gzhandler");
http_response_code(200); // Choisir le code de réponse selon ce qu'on veut faire
header('Server: Un serveur');
header('X-Robots-Tag: noindex, nofollow');
header('Content-Type: text/html; charset=utf-8');
echo 'Un truc ou rien';
ob_end_flush();
exit();
Pas de X-Forwarded-For ici, sauf si un proxy ou un CDN se trouve réellement devant le serveur. Ce header est un simple champ HTTP arbitraire, n'importe quel client peut le falsifier.
En l'absence de proxy de confiance identifié, REMOTE_ADDR reste la source fiable, sous peine de bannir une IP tierce usurpée à la place de celle du bot.
403, 200 ou tarpit : trois postures
| Réponse | Effet | Risque |
|---|---|---|
403 |
Signal net, simple à lire dans les logs | Aucun |
200 + contenu factice |
Fait perdre du temps au parsing du scanner | Indexation accidentelle si le leurre fuite ailleurs, à contrer avec X-Robots-Tag: noindex |
sleep() avant réponse |
Immobilise le scanner sur la connexion | Immobilise aussi un worker Apache/PHP-FPM côté serveur, risque d'auto-DoS en cas de scan massif |
Le 403 reste l'option la plus saine pour du monitoring propre. Les deux autres ajoutent de la friction côté attaquant, au prix d'un peu de complexité ou de risque côté serveur. À doser selon le volume réel de hits observé.
Les codes de réponses.
Limite
Ce honeypot ne piège que les bots qui lisent activement robots.txt pour y chercher des cibles. Les scanners qui balancent des chemins standards à l'aveugle sans jamais consulter le fichier (wp-admin, .env, xmlrpc.php…) peuvent passer à côté (sauf si on précise comme dans rèle Rewriterule ci-dessus). Le filtrage par User-Agent et par plage IP reste nécessaire en complément, voir l'article sur le filtrage et blocage de bots avec .htaccess.
Conclusion
Ah non, pas de conclusion.
That's all, Folks.