L'article ci-dessous vous décrit plusieurs méthodes et principes pour détecter un bot sur votre site web. Vous trouverez en bas de pages des exemples de scripts en php destiné à la détection des bots.
Il existe sur Internet de nombreux programmes automatisés appelé bots (abréviation de robots). Ces bots, ou crawler, ont été programmés dans des buts bien différents les uns des autres. Certains comme Googlebot, le bot de Google, explorent et indexent le web d'une façon raisonnable, c'est-à-dire en respectant les règles définies dans le fichier robots.txt et sans saturer votre serveur web. D'autre sont plus indélicats et possèdent d'autres buts, comme le récolte d'adresses e-mail ou le spam par referer. Dans ces derniers cas, il devient nécessaire de pouvoir détecter ces bots afin de pouvoir les bloquer.
Principes de détection de bots
- Ne pas faire confiance au bot en ce qui concerne le suivi des règles du w3c dans la gestion des cookies et des headers tels que referer, accept-lang, etc...
- Les seules données transmises par le visiteur qui seront prisent en considération sont son adresse ip et la résolution de son nom d'hôte.
- Un bot peut tenter de se faire passer pour un navigateur ou un autre bot en imitant le user-agent; il faut en outre tenir compte du fait que certains navigateurs possèdent la capacité de modifier leur user-agent afin de détecter un cloaking éventuel d'une page web. Le user-agent n'est donc pas suffisant pour détecter un bot.
- La résolution de l'adresse ip est toujours possible avec un bot connu tel que ceux de Google, Yahoo et autres. On peut déterminer dans ce cas le bot par son nom d'hôte.
- Un bot normal débute son exploration par la visite du fichier robots.txt. Il est possible de détecter la visite de ce fichier en effectuant de l'url rewriting vers un script php.
- Un bot voulant se faire passer pour un navigateur ne télécharge pas les fichiers .js, .css ainsi que les images. Cependant, cette règle n'est pas valide pour le premier accès au site. Pour détecter le téléchargement d'une image, on peut utiliser l'astuce suivante (le mieux est d'utiliser une image uniquement référencée depuis un fichier css):
- Choisir une image faisant partie de l'interface et présente sur toutes les pages à surveiller.
- Créer un script comprenant deux parties: la première enregistre la demande de l'image, la seconde ouvre l'image originale et l'envoie en sortie précédée d'un header Content-Type correct.
- Mettre en place une règle d'url rewriting de l'image vers le script, vous n'êtes donc pas obligé de modifier votre interface.
- Une autre méthode consiste à créer un lien caché (peu recommandable pour le référencement sur Google) que seuls les robots trouveront (ce genre de "piège à bots" sont appelés "pot de miel", ou "honey pot" en anglais). Faites pointer le lien sur une page spéciale qui peut se comporter de plusieurs façons, selon votre préférence. Vous pouvez créer une page vide contenant uniquement une balise meta robots afin qu'elle n'apparaisse pas dans l'index des moteurs de recherche ou alors utiliser une redirection 303 ou 307. Les deux scripts doivent enregistrer l'adresse ip comme étant celle d'un bot.
On peut alors détecter le passage d'un bot par les tests suivants:
Le nom d'hôte correspond à une liste de bots reconnus, ou
Le fichier robots.txt à été téléchargé, ou
L'image de test n'à pas été téléchargée, ou
L'adresse ip a visité le pot de miel
Il faut cependant garder en tête qu'il n'existe aucune méthode sûr à 100% pour détecter un bot. Surtout lors de la première visite.
La détection a besoin de quatre tables en base de données
hit_on_robots
| id | BIGINT | NOTNULL | auto-increment |
| ip | VARCHAR(15) | NOTNULL | |
| lastvisit | DATETIME | NOTNULL | |
hit_on_images
| id | BIGINT | NOTNULL | auto-increment |
| ip | VARCHAR(15) | NOTNULL | |
| lastvisit | DATETIME | NOTNULL | |
last_visits
| id | BIGINT | NOTNULL | auto-increment |
| ip | VARCHAR(15) | NOTNULL | |
| lastvisit | DATETIME | NOTNULL | |
detected_bots
| id | BIGINT | NOTNULL | auto-increment |
| ip | VARCHAR(15) | NOTNULL | |
| lastvisit | DATETIME | NOTNULL | |
Scripts php de détection
[Fichier de configuration]
<?php // Configuration $dbuser = "root"; $dbpass = "dbpass"; $dbhost = "localhost"; $dbname = "dbname"; $dbtblrobots = "hit_on_robots"; $dbtblimage = "hit_on_images"; $dbtbllastvisit = "last_visits"; $dbtbldetected = "detected_bots"; $robotfilepath = "./robots.txt"; $imagefilepath = "./image.gif"; // Connexion MySQL $cnx = mysql_connect($dbhost, $dbuser, $dbpass); if ($cnx !== false) mysql_select_db($dbname, $cnx); ?>
[Vérification de la présence d'un bot]
<?php //Détection par nom d'hôte des bots officiels (google, yahoo, …) Function IsKnowBot($host) { $parts = explode(".", $host); $ante = ""; if (count($parts) > 2) $ante = $parts[count($parts) – 2];
if (stristr($ante, "google") || stristr($ante, " yahoo") || stristr($ante, " msn") || stristr($ante, " live") || stristr($ante, " exabot")) return true; return false; }
Function IsBot() { include_once("[Fichier de configuration]"); //Récupération des informations $ua = $_SERVER["HTTP_USER_AGENT'"]; $ip = $_SERVER["REMOTE_ADDR"]; $host = isset($_SERVER["REMOTE_HOST"]) ? $_SERVER["REMOTE_HOST"] : gethostbyaddr ($ip); if (IsKnowBot($host)) return true;
if ($cnx === false) return false;
$now = time(); $datetimesqlnow = date('Y-m-d H:i:s', $now) $onehourago = $now – 3600; $datetimesql = date('Y-m-d H:i:s', $onehourago)
//Vérification de l'accès au "pot de miel" $req = "SELECT COUNT(*) FROM ".$dbtbldetected." WHERE ip='".$ip."' AND lastvisit >= '".$datetimesql."'";
$res = mysql_query($req, $cnx); if ($res === false) return false;
if (mysql_result($res, 0, 0) > 0) return true; //Vérification de l'accès au fichier robots.txt $req = "SELECT COUNT(*) FROM ".$dbtblrobots." WHERE ip='".$ip."' AND lastvisit >= '".$datetimesql."'";
$res = mysql_query($req, $cnx); if ($res === false) return false;
if (mysql_result($res, 0, 0) > 0) return true;
//Vérification de l'accès à l'image $req = "SELECT COUNT(*) FROM ".$dbtblimage." WHERE ip='".$ip."' AND lastvisit >= '".$datetimesql."'"; $res = mysql_query($req, $cnx); if ($res === false) return false;
//Attention, vrai lors de la première visite depuis un navigateur $hit_on_image = mysql_result($res, 0, 0) > 0;
//Alors on vérifie si c'est la première visite $req = "SELECT COUNT(*) FROM ".$dbtbllastvisit." WHERE ip='".$ip."' AND lastvisit >= '".$datetimesql."'";
$res = mysql_query($req, $cnx); if ($res === false) return false; $first_visit = mysql_result($res, 0, 0) == 0;
$req = "DELETE FROM ".$dbtbllastvisit." WHERE ip='".$ip."'"; mysql_query($req, $cnx);
$req = "INSERT INTO ".$dbtbllastvisit." (ip, lastvisit) VALUES('".$ip."','".$datetimesqlnow."')"; mysql_query($req, $cnx);
if (!hit_on_image && !first_visit) return true;
return false; ?>
[Code du script lié au fichier robots.txt]
<?php // Configuration include_once("[Fichier de configuration]");
if ($cnx !== false) { //Récupération des informations $ip = $_SERVER["REMOTE_ADDR"]; $req = "DELETE FROM ".$dbtblrobots." WHERE ip='".$ip."'"; mysql_query($req, $cnx); $req = "INSERT INTO ".$dbtblrobots." (ip, lastvisit) VALUES('".$ip."','".date('Y-m-d H:i:s', time())."')"; mysql_query($req, $cnx); }
header("Content-type: text/plain"); echo @implode("", @file($robotfilepath)); ?>
[Code du script lié à l'image.php]
<?php // Configuration include_once("[Fichier de configuration]");
if ($cnx !== false) { //Récupération des informations $ip = $_SERVER["REMOTE_ADDR"]; $req = "DELETE FROM ".$dbtblimage." WHERE ip='".$ip."'"; mysql_query($req, $cnx); $req = "INSERT INTO ".$dbtblimage." (ip, lastvisit) VALUES('".$ip."','".date('Y-m-d H:i:s', time())."')"; mysql_query($req, $cnx); }
$ext = strtolower(substr($imagefilepath, strlen($imagefilepath – 4)));
if ($ext == "gif") { $img = createimagefromgif($imagefilepath); header("Content-type: image/gif"); imagegif($img); } else if ($ext == "jpg" || $ext == "peg") { $img = imagecreatefromjpeg($imagefilepath); header("Content-type: image/jpeg"); imagejpeg($img); } else if ($ext == "png") { $img = imagecreatefrompng($imagefilepath); header("Content-type: image/png"); imagepng($img); } else { $img = imagecreate(10, 10); header("Content-type: image/jpeg"); imagejpeg($img); } ?>
[Code du script du pot de miel]
<?php // Configuration include_once("[Fichier de configuration]");
if ($cnx !== false) { //Récupération des informations $ip = $_SERVER["REMOTE_ADDR"]; $req = "DELETE FROM ".$dbtbldetected." WHERE ip='".$ip."'"; mysql_query($req, $cnx); $req = "INSERT INTO ".$dbtbldetected." (ip, lastvisit) VALUES('".$ip."','".date('Y-m-d H:i:s', time())."')"; mysql_query($req, $cnx); } ?>
|