Dans mon article précédent, j'ai pu démontrer un conteneur Kali Linux fonctionnant avec le navigateur Tor et connecté à son environnement de bureau avec un client VNC. J'ai vérifié que le navigateur Tor se connectait au réseau Tor pendant une session de navigation. Cette configuration me permettra de simuler le type de trafic qui pourrait provenir d'un attaquant ciblant un site Web.
Dans cette expérience, je vais utiliser Selenium pour automatiser le navigateur Tor afin de synthétiser les frappes au clavier et les événements de navigation via l'interface WebDriver du navigateur. Chaque crawler aura une adresse IP aléatoire fournie par le Tor Proxy intégré pour échapper à la détection. Après avoir enregistré les résultats en tant qu'objets JSON dans le système de fichiers local, j'utiliserai Python pour les traiter dans un seul fichier CSV. Enfin, je discuterai des contre-mesures qui peuvent être appliquées dans un centre de données et côté client pour tenter de détecter, de limiter et de bloquer l'activité des bots.
Tous les fichiers et les licences applicables sont disponibles dans ce référentiel open source : tor-driver-python
J'ai une formation en automatisation des tests et j'ai passé de nombreuses heures à concevoir des tests. J'ai également passé beaucoup de temps à travailler avec Selenium, et je l'ai utilisé dans de nombreux langages de programmation et paramètres différents pour automatiser les navigateurs Web à des fins de test. Il existe des scénarios où il n'est possible de tester une application Web qu'avec un vrai navigateur, et Selenium est un excellent outil pour cela.
Dans mon travail en tant qu'ingénieur DevOps, j'ai passé beaucoup de temps à me demander quoi faire avec les robots d'indexation Web qui frappent, et parfois carrément attaquent, les applications Web dont je suis responsable. J'ai pensé que ce serait une expérience intéressante d'explorer l'autre côté de cette question pour une fois.
Je veux voir jusqu'où je pourrais arriver à simuler une attaque d'un botnet à des fins éducatives et discuter des méthodes de lutte contre des choses comme le trafic suspect du réseau Tor dans un centre de données moderne. Les botnets sont couramment utilisés pour effectuer des attaques de Credential Stuffing. J'utiliserai une technique similaire pour rechercher des requêtes et recueillir des informations sur le Web.
Le credential stuffing est l'injection automatisée de paires de nom d'utilisateur et de mot de passe volées ("identifiants") dans les formulaires de connexion du site Web, afin d'accéder frauduleusement aux comptes d'utilisateurs. 1
Afin d'éviter les problèmes éthiques, tout en essayant de rester fidèle à la tâche. J'apporte les modifications suivantes au scénario :
robots.txt
permissifs, et les termes et conditions ont été vérifiés au moment de la rédaction, ce qui n'empêcherait pas l'exploration. Par exemple , les termes et conditions d'IMDB interdisent explicitement l'exploration sans consentement écrit.
Le protocole d'exclusion des robots est un moyen pour les webmasters d'indiquer aux robots d'exploration où ils se trouvent et où ils ne sont pas autorisés à recueillir des informations. Plus d'informations et d'exemples peuvent être trouvés sur le site Web robotstxt.org . J'ai trouvé un article : Liste des moteurs de recherche alternatifs en essayant d'en trouver un qui permettait le web scraping sur la page des résultats de recherche. Vous trouverez ci-dessous un résumé de cette recherche.
Moteur de recherche | URL robots.txt | L'exploration est-elle autorisée ? |
---|---|---|
Non, mais a une API | ||
Non, mais a une API | ||
Non | ||
Non, mais a une API | ||
Oui, mais pas exactement ce que je cherchais | ||
Oui |
Quelques autres ressources que j'ai trouvées utiles lors de mes recherches sur ce sujet :
Je vais éviter d'utiliser des bibliothèques autres que le sélénium pour cet exemple. Il y a des modèles vraiment basiques que je veux démontrer et je ne veux pas m'enliser avec un langage spécifique à un domaine (DSL) particulier qui pourrait rendre plus difficile la compréhension de ce qui se passe.
Cependant, je pense que l'utilisation d'un framework d'exécution de tests est un excellent moyen d'organiser ce type de code. L'ajout d'un framework peut résoudre de nombreux problèmes liés à la structure générale du code, à la logique de nouvelle tentative et même à la création de rapports.
Il y a un modèle de base dans la façon dont je manipule une page dans une session WebDriver. J'ajoute également une pause après chaque action effectuée. L'automatisation du navigateur peut être irrégulière. Les délais d'attente ajoutent beaucoup de stabilité au crawl et limitent considérablement les chances d'obtenir un débit limité et bloqué. Chaque fois que nécessaire, j'augmente également le crawl avec des appels d'API vers d'autres moteurs de recherche ou sources d'informations.
J'ai adopté une approche très simple pour les sélecteurs. J'utilise à la fois les sélecteurs xpath et css disponibles dans le navigateur. Se concentrant principalement sur les balises d'ancrage et les fragments d'URL pour naviguer entre les pages lors d'un crawl.
J'utilise les conditions attendues pour attendre que les éléments soient présents avant d'essayer de cliquer dessus. Le projet Selenium contient beaucoup de documentation, mais j'ai également trouvé que la discussion sur les conditions d'attente avec des exemples d'utilisation sur Stack Overflow était une ressource inestimable.
Il existe un projet PyPi appelé tbselenium qui a une fonction similaire. Pour cette expérience, j'ai fait référence à la configuration du profil Firefox, mais je n'ai eu besoin d'aucune des autres fonctionnalités incluses par tbselenium. La complexité supplémentaire des conteneurs n'ayant pas d'accès root contribuait à rendre le débogage plus difficile. Cela a ajouté à la motivation pour limiter les dépendances et essayer des solutions préexistantes simples. Par exemple, il existe de nombreux endroits où j'utilise des outils et des sous-shells Linux au lieu d'implémenter directement des solutions python pures.
La classe finie est d'environ 150 lignes de Python. Je pense qu'il sera plus facile d'analyser ce qui se passe en profondeur avec moins à revoir. J'ai beaucoup appris sur le fonctionnement du lanceur de navigateur Tor et sur la configuration des profils Firefox. Ce profil a été amassé à partir de plusieurs sources en ligne, et ils sont mentionnés dans le code source ainsi que dans ce document.
J'ai résumé le démarrage, le démontage et un élément de logique de navigation très courant dans une classe appelée TorDriver
. C'est une classe très simple qui configure un profil Firefox avec le lanceur de navigateur Tor. Il a une méthode pour vérifier si un élément est visible sur la page, et une autre qui vérifie que le socket proxy est opérationnel. La configuration et le débogage du profil Firefox ont été largement informés par une discussion sur Stack Overflow : Open Tor Browser with Selenium .
Le fichier complété peut être trouvé ici : tor-driver-python/torDriver.py
Importation de sélénium, pprint, sous-processus et socket pour les composants setup et WebDriver.
La méthode suivante résume la vérification d'un élément et renvoie True
ou False
s'il est visible dans un délai d'attente.
Le port proxy doit être actif avant de lui envoyer des signaux. Après quelques exemples dans Stack Overflow sur le test des connexions de socket en Python, j'ai trouvé ceci :
La majeure partie du module est une classe qui contrôle le profil Firefox, télécharge geckodriver et lance torbrowser-launcher.
Ici, j'ai une configuration de base et quelques moyens de remplacer les choses, mais surtout en gardant cela aussi simple que possible :
Le profil Firefox doit être configuré au minimum pour se connecter au port proxy, j'avais également désactivé le javascript avec.
Cela utilise le profil et le binaire de TorDriver pour initialiser un pilote
Ajout d'une méthode pour télécharger et extraire geckodriver dans un sous-processus. Il convient de mentionner que, d'une manière ou d'une autre, lors de son exécution dans le conteneur, le tar.gz
n'est plus compressé et qu'il a simplement besoin d'être désarchivé. Plus d'informations sur l'erreur sont disponibles ici : stdin : pas d'erreur de format gzip
Jusqu'à ce que le socket réponde, réessayez de vous connecter au port proxy :
Dans cet exemple, j'ai adopté l'approche suivante en deux phases. La première phase est la collecte d'informations et la phase suivante consiste à traiter les informations. De cette façon, je ne suis pas lié à la connectivité réseau pour l'ensemble du processus et je peux réessayer d'analyser les résultats autant de fois que nécessaire sans revenir au matériel source.
Le fichier complet peut être trouvé ici : tor-driver-python/crawler.py
Le robot d'exploration lit un fichier texte et utilise ces informations pour remplir des requêtes dans la session WebDriver. L'état du crawl est conservé dans un dossier de fichiers json un par requête. J'essaie de faire le traitement minimum absolument nécessaire pour exporter les informations une seule fois et tout traitement ultérieur peut se produire dans les données existantes au lieu de revenir au(x) site(s).
J'utilise un fichier texte pour stocker les recherches. J'ai choisi un fichier texte car il est très facile à restructurer. La modification de texte est un obstacle faible pour démarrer une analyse avec de nouvelles informations ou pour reprendre une analyse qui a échoué en cours de route. Si ce robot avait des exigences de données plus complexes, j'envisagerais plutôt d'utiliser une base de données. Cela permettra de mettre en œuvre une API pour contrôler les analyses avec une interface utilisateur personnalisée, pour les rapports.
Des exemples de fichiers se trouvent déjà dans le dossier des résultats du référentiel : tor-driver-python/results
Dans un robot d'exploration plus robuste, je suggérerais d'utiliser une technologie de base de données réelle. Cela suffit pour savoir facilement où la collecte de données s'est arrêtée et faciliter le redémarrage.
Le robot d'exploration peut être exécuté à partir du conteneur avec les commandes suivantes. Le générateur de rapport nécessite la présence de fichiers JSON, un exemple de fichier CSV d'exportation peut être trouvé ici :
Démarrez le conteneur :
docker run -it --rm -p 5901:5901 -v "${HOME}/src":/src excitingtheory/kalilinux-xvfb:torbrowser
Démarrez un serveur VNC dans le conteneur, il vous demandera les mots de passe de session :
/opt/start-vnc-server-once.sh
Commencez l'exploration depuis la session VNC :
python3 crawler.py
Le crawler attendra l'initialisation du navigateur Tor, et malheureusement, c'est une étape manuelle. Cliquez simplement sur la case à cocher, puis cliquez sur se connecter. Voir la démo vidéo pour un exemple.
Le script de rapport générera un fichier de valeurs séparées par des virgules (CSV) à partir du
Fichiers de résultats JSON (JavaScript Object Notation) que le robot d'exploration enregistre tout au long de l'exploration. J'ai choisi le format CSV car c'est un format plus courant pour le partage avec des collègues, mais toujours facile à importer dans d'autres outils pour une analyse plus approfondie.
Le fichier complet peut être trouvé ici : tor-driver-python/report.py
Cela utilise des bibliothèques Python intégrées pour lire JSON, écrire du CSV et analyser des URL pour le formatage et la présentation des données. Parcourt ensuite les résultats et les charge pour commencer le traitement des données.
Il s'agit de la fonctionnalité principale du générateur de rapports. Cela effectue une présentation finale et un classement des données capturées dans les objets de résultats. En règle générale, les URL ne sont utiles que pour le mouvement fonctionnel des robots d'exploration sur un site, et non comme une capture de données finale, mais c'est un bon début pour personnaliser davantage l'extraction de données.
Les résultats de l'analyse sont enregistrés dans le répertoire ./results
sous forme de fichiers JSON. Je vais utiliser le script suivant pour générer un rapport à partir des données.
python3 report.py
Un exemple de fichier CSV de sortie peut être trouvé ici : tor-driver-python/output.csv
Il existe plusieurs façons de détecter et d'atténuer l'activité des bots. Je me concentrerai principalement sur le côté centre de données, mais je discuterai également de certaines méthodes de détection côté client. Cependant, le client ne peut jamais vraiment faire confiance, car les signaux côté client peuvent changer à tout moment et peuvent être usurpés. Je pense qu'il est important de garder cela à l'esprit lors de la conception d'un système de détection. Dans le centre de données, il existe deux formes de protection dont je vais parler : la limitation du débit et le blocage de la réputation.
Il existe plusieurs façons de détecter une session WebDriver active côté client avec juste javascript : un problème quelque peu connexe dans Github va plus en détail . Essentiellement, parce que le protocole WebDriver modifie les objets document et fenêtre, il peut être détecté dans le code côté client.
Je vais me concentrer sur les solutions avec lesquelles j'ai le plus d'expérience, Fastly, AWS WAF et Nginx. CloudFlare a été une surprise totale, je vais donc également parler de leur offre.
Les règles basées sur le taux d' AWS Web Application Firewall (WAF) peuvent également être utilisées pour bloquer les niveaux d'activité de déni de service, et il existe des règles par défaut qui peuvent également être utilisées pour détecter le trafic réseau Tor, consultez la documentation sur les règles de réputation IP pour plus d'informations. Une autre approche courante consiste à bloquer tout le trafic provenant d'autres centres de données, ce qui est sûr si le public cible est les consommateurs. Cependant, les entreprises pourraient utiliser un VPN cloud et d'autres technologies susceptibles de nuire au trafic légitime.
Signal Science de Fastly, une solution très populaire, peut être utilisée pour détecter spécifiquement le trafic Tor. Tout d'abord, ils peuvent se protéger des attaques DDOS, consultez leur page DDOS Mitigation pour plus d'informations. Deuxièmement, ils peuvent détecter le trafic Tor et le bloquer. Voici la documentation Utilisation des signaux système qui couvre cela.
Pour Nginx, il existe également des articles à ce sujet : Comment bloquer le trafic anonyme avec Nginx ou à l'intérieur de votre application Web . Essentiellement, en appelant les API pour obtenir des informations sur les nœuds de sortie Tor, des règles de blocage IP peuvent être générées et appliquées à Nginx selon un calendrier.
Dans un contraste surprenant avec les fournisseurs de cloud ci-dessus, CloudFlare offre un support pour les clients Tor. Je suis tombé sur leur documentation de support Tor !? où ils discutent de la capacité de servir du contenu aux utilisateurs de Tor à partir du réseau. Je pense que c'est une approche vraiment intéressante, et j'ai hâte de l'explorer davantage à l'avenir.
WebDriver est un puissant outil de test et peut également être utilisé pour collecter des informations dans des endroits où l'accès à une API n'est pas possible. Par exemple : l'accès est autrement restreint, censuré, trop cher ou généralement enfermé derrière des pratiques anticoncurrentielles. Mieux encore, combinez les données recueillies à partir de l'exploration Web avec les informations recueillies à partir des API.
Il s'agit d'un exercice important car il devient de plus en plus difficile d'empêcher le trafic malveillant des bots, et ce n'est pas une bonne pratique de sécurité d'attendre qu'une attaque se produise pour réfléchir à la manière de l'atténuer. Je pense que tous ceux qui sont chargés de mettre des informations en ligne devraient savoir comment les informations piratées seront utilisées contre les systèmes dont ils sont responsables. Dans un scénario simplifié, avec des contraintes éthiques, je l'ai démontré en procédant comme suit :