Filtrage des accès et détection des mauvais robots

Auteur Message
Ici seront rapportées des notes sur la détection des mauvais robots et le filtrage des IPs qui abusent.

La commande host

Nom d’hôte versus nom de domaine.

On peut se demander ce qui distingue un nom d’hôte d’un nom de domaine, comme les deux se ressemblent littéralement. Un hôte, c’est une machine, un domaine, c’est un service. Sur un même machine, plusieurs sites web peuvent être hébergés. Ceci fait que pour une adresse IP, il pourrait y avoir plusieurs nom de domaines, mais l’IP n’aura qu’un seul nom d’hôte. Le même principe vaut pour les sites web et avec toutes autres choses joignables depuis l’extérieur de l’hôte, comme un serveur mail.

Un exemple avec le forum. La command ping informe que son adresse IP actuelle est 185.31.40.19. La commande host 185.31.40.19 répond http9.paris1.alwaysdata.com. Le point à la fin fait partie de la réponse, je crois qu’il vient des enregistrement DNS. Ce nom d’hôte, c’est celui de l’hébergement du forum chez AlwaysData et ils en ont plusieurs comme ça.

Ne pas oublier cette distinction entre nom d’hôte et nom de domaine.

Interprétation des noms d’hôte.

La commande host peut être utile pour filtrer certaines IP, après qu’on ait choisi des IPs semblant suspectes, à surveiller, par exemple parce qu’elles apparaissent anormalement souvent. Ensuite, on peut essayer de se faire une idée d’après la réponse, si on y arrive.

Les noms d’hôte, peuvent avoir une hiérarchie, comme les nom de domaine, il peut y avoir des sous‑nom d’hôte (si c’est le bon mot), comme il peut y avoir des sous‑domaines dans un nom de domaine. Ça peut être important à noter. Par exemple le nom d’hôte googleusercontents.com, qui est très suspect et n’est pas le moteur de recherche du monpole Google, a peut apparaître comme bc.googleusercontents.com ou gae.googleusercontents.com. Cette organisation peut être importante pour évaluer un nom d’hôte.

Le nom d’hôte renvoyé contient toujours (ou presque toujours, je ne sais pas), une adresse IP et ce n’est pas toujours (mais ça peut l’être) l’adresse IP pour laquelle on fait une requête d’information. Vous pouvez faire quelques essais avec la commande, pour en avoir une idée. Il peut être pertinent de simplifier le nom d’hôte, pour l’interpréter automatiquement. Je n’ai qu’une heuristique pour ça, mais n’en parle pas avant de l’avoir suffisamment testé.

Mettre en place un cache et l’utiliser.

La commande host fait des requêtes à des serveurs externes, alors il faut essayer d’être économe avec et mettre les résultats dans un cache où on peut essayer de retrouver une réponse pour une IP, avant seulement de faire appel à la commande. Ça permet de ne pas abuser d’un service externe, pour ne pas faire ce qu’on reproche aux robots qui abusent et ça permet aussi de rendre le programme d’analyse plus rapide, parce que la commande host, même si elle semble être rapide, montre sa lenteur quand elle est souvent invoquée.

Le cache doit pouvoir avoir un stockage pérenne, parce que s’il faut refaire toute les requête à chaque démarrage d’une application qui fait un audit, c’est du gaspillage. On peut utiliser par exemple une base de donnée légère, genre SQLite ou autre, ou faire du stockage persistant avec le langage qu’on utilise, par exemple pickle en Python ou faire un stockage fait maison, comme ça va le mieux. Ça dépend aussi de la quantité de donnée. Avec pickle par exemple, si on y stocke un dictionnaire, il doit être rechargé entièrement à chaque fois. S’il est vraiment très volumineux, une base de donnée peut être préférable. Avec pickle, attention à choisir le protocole qui convient aux gros objets. Le meilleure supporté actuellement, est le numéro 5.

Il faut faire en sorte que ce stockage persistant soit sauvegardé même en cas d’arrêt imprévu du programme d’analyse, par exemple par une exception. Parce que tout le temps que le programme a tourné, il a put obtenir des résultats de requêtes qui il est judicieux de ne pas refaire.

Une base de donnée peut être plus pérenne qu’une sérialisation dépendant de la version d’un langage ou de sa plateforme, ce qui est le cas avec pickle de Python. Dans le cas d’une sérialisation faite maison, le problème ne se posera probablement pas, mais il s’agira peut‑être de quelque chose qui charge tout en mémoire, ce qui peut poser problème quand il y a beaucoup de donnée. La base de données SQLite, ne charge pas tout en mémoire, mais ce n’est pas le cas de toute. Avec l’API de Python, on peut directement utiliser une base SQLite, mais ce n’est pas toujours l’idéal, parce que l’interface est tellement abstraite et cherche tellement à masquer les particularités, que ça en pose des problèmes technique, et des problèmes de lenteur aussi. Pour SQLite avec Python, j’ai personnellement une préférence pour APSW, mais APSW n’est pas disponible pour MacOS. Voir cette page qui propose deux solution, dont une pour MacOS et ma préférée (il n’y en a que deux) : SQlite (wiki.python.org). Un autre pilote semblant intéressant ici, mais ne l’ayant pas testé, n’en parlerai pas : cysqlite - a new sqlite driver (charlesleifer.com). Ce n’est pas parce que Python et SQLite sont mentionné, que ce sont les seuls solutions, il est possible d’en préférer d’autres.

Le status retourné par la commande.

Normalement la commande host renvoi un status d’échec qui vaut 1 quand elle ne peut pas retourner de réponse. Mais il existe des cas où elle retourne zéro alors qu’elle renvoi une réponse qui signifie qu’elle n’a rien trouvé. Un exemple de mauvaise réponse avec pourtant un status égal à zéro, est “ 92.14.137.204.in-addr.arpa has no PTR record ”. On peut rencontrer ce cas avec des IPs comme 204.137.14.54 ou 185.128.239.125 et d’autres. Un autre cas est avec une forme de réponse vide. Par exemple host 89.169.12.129 donne la réponse “ 129.12.169.89.in-addr.arpa domain name pointer . ”, qui ne contient pas de nom d’hôte, alors que le status renvoyé est bien zéro. Il faut détecter ces cas.

La commande host fait des requêtes externes, comme toutes les commandes en rapport avec les DNS. Il faudrait savoir ce que renvoi la commande, dans le cas où l’un des serveurs remplissant ce service, considère qu’il reçoit trop de requêtes. Je l’ignore, et n’ai qu’une heuristique pour le détecter mais n’en fait pas part pour le moment, faute de l’avoir suffisamment testé (elle m’a renvoyé un second faux‑positif).