In meinem vorherigen Artikel konnte ich einen Kali-Linux-Container demonstrieren, der mit dem Tor-Browser läuft und über einen VNC-Client mit seiner Desktop-Umgebung verbunden ist. Ich habe überprüft, dass der Tor-Browser während einer Browsersitzung eine Verbindung zum Tor-Netzwerk herstellte. Mit diesem Setup kann ich die Art des Datenverkehrs simulieren, der von einem Angreifer ausgehen könnte, der eine Website angreift.
In diesem Experiment werde ich Selenium verwenden, um den Tor-Browser zu automatisieren, um Tastenanschläge und Navigationsereignisse über die WebDriver-Schnittstelle des Browsers zu synthetisieren. Jeder Crawler erhält eine zufällige IP-Adresse, die vom eingebetteten Tor-Proxy bereitgestellt wird, um einer Erkennung zu entgehen. Nachdem ich die Ergebnisse als JSON-Objekte im lokalen Dateisystem gespeichert habe, werde ich sie mit Python in einer einzigen CSV-Datei verarbeiten. Abschließend werde ich diskutieren, welche Gegenmaßnahmen in einem Rechenzentrum und auf Client-Seite angewendet werden können, um zu versuchen, Bot-Aktivitäten zu erkennen, zu begrenzen und zu blockieren.
Alle Dateien und anwendbaren Lizenzen sind in diesem Open-Source-Repository verfügbar: tor-driver-python
Ich habe einen Hintergrund in der Testautomatisierung und habe viele Stunden damit verbracht, Tests zu entwerfen. Ich habe auch viel Zeit mit Selenium verbracht und es in vielen verschiedenen Programmiersprachen und -einstellungen verwendet, um Webbrowser zu Testzwecken zu automatisieren. Es gibt Szenarien, in denen es nur möglich ist, eine Webanwendung mit einem echten Browser zu testen, und Selenium ist dafür ein großartiges Tool.
Bei meiner Arbeit als DevOps-Ingenieur habe ich nicht wenig Zeit damit verbracht, mir Gedanken darüber zu machen, was ich mit den Webcrawlern tun soll, die die Webanwendungen, für die ich verantwortlich bin, angreifen und manchmal sogar direkt angreifen. Ich dachte, es wäre ein interessantes Experiment, einmal die andere Seite dieses Themas zu erkunden.
Ich möchte sehen, wie nah ich an die Simulation eines Botnet-Angriffs zu Bildungszwecken herankomme, und um Methoden zur Bekämpfung von Dingen wie verdächtigem Tor-Netzwerkverkehr in einem modernen Rechenzentrum zu diskutieren. Botnets werden häufig zur Durchführung von Credential-Stuffing-Angriffen eingesetzt. Ich werde eine ähnliche Technik verwenden, um Suchanfragen zu stellen und Informationen aus dem Internet zu sammeln.
Unter Credential Stuffing versteht man die automatisierte Einschleusung gestohlener Benutzernamen- und Passwortpaare („Anmeldeinformationen“) in Anmeldeformulare für Websites, um sich auf betrügerische Weise Zugriff auf Benutzerkonten zu verschaffen. 1
Um ethische Probleme zu vermeiden und gleichzeitig zu versuchen, der Aufgabe treu zu bleiben. Ich nehme folgende Änderungen am Szenario vor:
robots.txt
Dateien ab, und zum Zeitpunkt des Schreibens wurden die Allgemeinen Geschäftsbedingungen überprüft, die das Crawlen nicht ausschließen würden. Beispielsweise verbieten die Allgemeinen Geschäftsbedingungen von IMDB ausdrücklich das Crawlen ohne schriftliche Zustimmung.
Das Robots Exclusion Protocol ist eine Möglichkeit für Webmaster, Crawlern mitzuteilen, wo sie sich befinden und woher sie keine Informationen sammeln dürfen. Weitere Informationen und Beispiele finden Sie auf der Website robotstxt.org . Ich habe einen Artikel gefunden: Liste alternativer Suchmaschinen, als ich versucht habe, eine zu finden, die Web Scraping auf der Suchergebnisseite ermöglicht. Nachfolgend finden Sie eine Zusammenfassung dieser Forschung.
Suchmaschine | robots.txt-URL | Ist Krabbeln erlaubt? |
---|---|---|
Nein, hat aber eine API | ||
Nein, hat aber eine API | ||
NEIN | ||
Nein, hat aber eine API | ||
Ja, aber nicht genau das, was ich gesucht habe | ||
Ja |
Einige andere Ressourcen, die ich bei der Recherche zu diesem Thema nützlich fand:
Ich werde in diesem Beispiel die Verwendung anderer Bibliotheken als Selenium vermeiden. Es gibt einige wirklich grundlegende Muster, die ich demonstrieren möchte, und ich möchte mich nicht in einer bestimmten domänenspezifischen Sprache (DSL) festsetzen, die es schwieriger machen könnte, zu verstehen, was vor sich geht.
Ich denke jedoch, dass die Verwendung eines Testlauf-Frameworks eine großartige Möglichkeit ist, diese Art von Code zu organisieren. Durch das Hinzufügen eines Frameworks können viele Probleme im Zusammenhang mit der allgemeinen Codestruktur, der Wiederholungslogik und sogar der Berichterstellung gelöst werden.
Es gibt ein Grundmuster dafür, wie ich eine Seite in einer WebDriver-Sitzung bearbeite. Außerdem füge ich nach jeder ausgeführten Aktion eine Pause hinzu. Die Browserautomatisierung kann unzuverlässig sein. Die Zeitüberschreitungen erhöhen die Stabilität des Crawls erheblich und begrenzen die Wahrscheinlichkeit einer Ratenbegrenzung und -blockierung erheblich. Bei Bedarf erweitere ich das Crawling auch durch API-Aufrufe an andere Suchmaschinen oder Informationsquellen.
Bei den Selektoren habe ich einen wirklich einfachen Ansatz gewählt. Ich verwende sowohl die XPath- als auch die CSS- Selektoren, die im Browser verfügbar sind. Der Schwerpunkt liegt hauptsächlich auf Anker-Tags und URL-Fragmenten zum Navigieren zwischen Seiten während eines Crawls.
Ich verwende erwartete Bedingungen , um darauf zu warten, dass die Elemente vorhanden sind, bevor ich versuche, darauf zu klicken. Das Selenium-Projekt verfügt über eine Menge Dokumentation, aber ich fand auch, dass die Diskussion über Wartebedingungen mit Beispielverwendungen auf Stack Overflow eine unschätzbare Ressource ist.
Es gibt ein bestehendes PyPi-Projekt namens tbselenium , das eine ähnliche Funktion hat. Für dieses Experiment habe ich auf die Einrichtung des Firefox-Profils verwiesen, benötigte aber keine der anderen Funktionen, die tbselenium enthält. Die zusätzliche Komplexität, die dadurch entsteht, dass die Container keinen Root-Zugriff haben, trug dazu bei, dass das Debuggen schwieriger wurde. Dies verstärkte die Motivation, Abhängigkeiten zu begrenzen und einfache, bereits vorhandene Lösungen auszuprobieren. Beispielsweise verwende ich an vielen Stellen Linux-Tools und Sub-Shells, anstatt reine Python-Lösungen direkt zu implementieren.
Die fertige Klasse umfasst etwa 150 Zeilen Python. Ich denke, es wird einfacher sein, das Geschehen eingehend zu analysieren und weniger zu überprüfen. Ich habe viel darüber gelernt, wie der Tor Browser Launcher funktioniert und wie man Firefox-Profile konfiguriert. Dieses Profil wurde aus mehreren Online-Quellen zusammengestellt und sie werden sowohl im Quellcode als auch in diesem Dokument erwähnt.
Ich habe das Starten, Herunterfahren und einen sehr häufigen Teil der Navigationslogik in einer Klasse namens TorDriver
abstrahiert. Es handelt sich um eine sehr einfache Klasse, die mit dem Tor Browser Launcher ein Firefox-Profil einrichtet. Es verfügt über eine Methode zum Überprüfen, ob ein Element auf der Seite sichtbar ist, und eine weitere, die überprüft, ob der Proxy-Socket aktiv ist. Das Einrichten und Debuggen des Firefox-Profils wurde größtenteils durch eine Stack Overflow-Diskussion beeinflusst: Open Tor Browser with Selenium .
Die fertige Datei finden Sie hier: tor-driver-python/torDriver.py
Importieren von Selenium, Pprint, Subprozess und Socket für die Setup- und WebDriver-Komponenten.
Die folgende Methode abstrahiert die Suche nach einem Element und gibt True
“ oder False
zurück, wenn es innerhalb einer Zeitüberschreitung sichtbar ist.
Der Proxy-Port muss aktiv sein, bevor Signale an ihn gesendet werden können. Nach einigen Beispielen in Stack Overflow zum Testen von Socket-Verbindungen in Python bin ich auf Folgendes gekommen:
Der Großteil des Moduls ist eine Klasse, die das Firefox-Profil steuert, den Geckodriver herunterlädt und den Torbrowser-Launcher initiiert.
Hier habe ich eine Grundkonfiguration und einige Möglichkeiten, Dinge zu überschreiben, aber meistens halte ich es so einfach wie möglich:
Das Firefox-Profil muss mindestens konfiguriert sein, um eine Verbindung zum Proxy-Port herzustellen. Ich hatte damit auch Javascript deaktiviert.
Dabei werden das Profil und die Binärdatei von TorDriver verwendet, um einen Treiber zu initialisieren
Hinzufügen einer Methode zum Herunterladen und Extrahieren von Geckodriver in einem Unterprozess. Erwähnenswert ist, dass tar.gz
bei der Ausführung im Container irgendwie nicht mehr komprimiert wird und lediglich dearchiviert werden muss. Weitere Informationen zum Fehler finden Sie hier: stdin: not in gzip format error
Versuchen Sie erneut, eine Verbindung zum Proxy-Port herzustellen, bis der Socket antwortet:
In diesem Beispiel habe ich den folgenden zweiphasigen Ansatz gewählt. In der ersten Phase werden Informationen gesammelt, in der darauffolgenden Phase werden die Informationen verarbeitet. Auf diese Weise bin ich für den gesamten Prozess nicht an die Netzwerkkonnektivität gebunden und kann das Parsen der Ergebnisse so oft wie nötig wiederholen, ohne zum Quellmaterial zurückkehren zu müssen.
Die vollständige Datei finden Sie hier: tor-driver-python/crawler.py
Der Crawler liest eine Textdatei ein und verwendet diese Informationen, um Abfragen in der WebDriver-Sitzung zu füllen. Der Status des Crawls wird in einem Ordner mit JSON-Dateien (eine pro Abfrage) gespeichert. Ich versuche, die für den einmaligen Export der Informationen unbedingt erforderliche Mindestverarbeitung durchzuführen, und jede weitere Verarbeitung kann in den vorhandenen Daten erfolgen, anstatt zu den Websites zurückzukehren.
Ich verwende eine Textdatei zum Speichern von Suchen. Ich habe mich für eine Textdatei entschieden, weil sie sehr einfach umzustrukturieren ist. Das Bearbeiten von Text stellt eine niedrige Hürde dar, um einen Crawl mit neuen Informationen zu beginnen oder einen Crawl fortzusetzen, der auf halbem Weg fehlgeschlagen ist. Wenn dieser Crawler komplexere Datenanforderungen hätte, würde ich stattdessen die Verwendung einer Datenbank in Betracht ziehen. Dies ermöglicht die Implementierung einer API zur Steuerung von Scans mit einer benutzerdefinierten Benutzeroberfläche für die Berichterstellung.
Beispieldateien befinden sich bereits im Ergebnisordner im Repo: tor-driver-python/results
In einem robusteren Crawler würde ich die Verwendung einer tatsächlichen Datenbanktechnologie vorschlagen. Dies reicht aus, um leicht zu erkennen, wo die Datenerfassung gestoppt wurde, und um einen Neustart zu erleichtern.
Der Crawler kann mit den folgenden Befehlen aus dem Container ausgeführt werden. Für den Berichtsgenerator müssen JSON-Dateien vorhanden sein. Eine Beispiel-Export-CSV-Datei finden Sie hier:
Starten Sie den Container:
docker run -it --rm -p 5901:5901 -v "${HOME}/src":/src excitingtheory/kalilinux-xvfb:torbrowser
Starten Sie einen VNC-Server im Container. Er fordert zur Eingabe von Sitzungskennwörtern auf:
/opt/start-vnc-server-once.sh
Beginnen Sie den Crawl innerhalb der VNC-Sitzung:
python3 crawler.py
Der Crawler wartet auf die Initialisierung des Tor-Browsers, was leider ein manueller Schritt ist. Klicken Sie einfach auf das Kontrollkästchen und dann auf „Verbinden“. Ein Beispiel finden Sie in der Videodemo.
Das Berichtsskript generiert daraus eine CSV-Datei (Comma Separated Value).
JSON-Ergebnisdateien (JavaScript Object Notation), die der Crawler während des Crawls speichert. Ich habe mich für das CSV-Format entschieden, weil es ein gebräuchlicheres Format zum Teilen mit Kollegen ist, sich aber dennoch leicht in andere Tools zur weiteren Analyse importieren lässt.
Die vollständige Datei finden Sie hier: tor-driver-python/report.py
Dabei werden integrierte Python-Bibliotheken verwendet, um JSON zu lesen, CSV zu schreiben und URLs zur Formatierung und Datenpräsentation zu analysieren. Dann durchläuft es die Ergebnisse und lädt sie, um mit der Datenverarbeitung zu beginnen.
Dies ist die Kernfunktionalität des Berichtsgenerators. Dies führt zu einer abschließenden Präsentation und Sortierung der in den Ergebnisobjekten erfassten Daten. Normalerweise sind URLs nur für die funktionale Bewegung von Crawlern durch eine Website nützlich und nicht für die endgültige Datenerfassung. Sie sind jedoch ein guter Anfang für die Anpassung der weiteren Datenextraktion.
Die Ergebnisse des Crawls werden im Verzeichnis ./results
als JSON-Dateien gespeichert. Ich werde das folgende Skript verwenden, um aus den Daten einen Bericht zu erstellen.
python3 report.py
Eine Beispiel-CSV-Ausgabedatei finden Sie hier: tor-driver-python/output.csv
Es gibt verschiedene Möglichkeiten, Bot-Aktivitäten zu erkennen und einzudämmen. Ich werde mich hauptsächlich auf die Rechenzentrumsseite konzentrieren, aber auch einige clientseitige Erkennungsmethoden besprechen. Dem Client kann man jedoch nie wirklich vertrauen, da sich die Signale auf der Clientseite jederzeit ändern und gefälscht werden können. Ich denke, es ist wichtig, dies bei der Entwicklung eines Erkennungssystems zu berücksichtigen. Im Rechenzentrum gibt es zwei Formen des Schutzes, die ich besprechen werde: Ratenbegrenzung und Reputationsblockierung.
Es gibt mehrere Möglichkeiten, eine aktive WebDriver-Sitzung auf der Clientseite nur mit Javascript zu erkennen: Auf ein ähnliches Problem in Github wird näher eingegangen . Da das WebDriver-Protokoll die Dokument- und Fensterobjekte ändert, kann es im Wesentlichen im clientseitigen Code erkannt werden.
Ich werde mich auf die Lösungen konzentrieren, mit denen ich am meisten Erfahrung habe: Fastly, AWS WAF und Nginx. CloudFlare war eine völlige Überraschung, daher werde ich auch über ihr Angebot sprechen.
Die ratenbasierten Regeln der AWS Web Application Firewall (WAF) können auch zum Blockieren von Denial-of-Service-Aktivitäten verwendet werden, und es gibt Standardregeln, die auch zum Erkennen des Tor-Netzwerkverkehrs verwendet werden können. Weitere Informationen finden Sie in der Dokumentation zu IP-Reputationsregeln . Ein weiterer gängiger Ansatz besteht darin, den gesamten Datenverkehr von anderen Rechenzentren zu blockieren. Dies ist sicher, wenn die Zielgruppe Verbraucher sind. Allerdings könnten Unternehmen Cloud-VPN und andere Technologien nutzen, die den legitimen Datenverkehr schädigen können.
Mit Signal Science von Fastly lässt sich Tor-Verkehr gezielt erkennen, eine sehr beliebte Lösung. Erstens können sie sich vor DDOS-Angriffen schützen. Weitere Informationen finden Sie auf der Seite zur DDOS-Mitigation . Zweitens können sie Tor-Verkehr erkennen und blockieren. Hier ist die Dokumentation zur Verwendung von Systemsignalen , die dies behandelt.
Für Nginx gibt es auch einige Artikel dazu: So blockieren Sie anonymen Datenverkehr mit Nginx oder innerhalb Ihrer Webanwendung . Im Wesentlichen können durch Aufrufen von APIs, um Informationen über Tor-Exit-Knoten zu erhalten, IP-Blockierungsregeln generiert und nach einem Zeitplan auf Nginx angewendet werden.
Im überraschenden Gegensatz zu den oben genannten Cloud-Anbietern bietet CloudFlare Support für Tor-Clients an. Ich bin auf ihre Tor-Support-Dokumentation gestoßen!? Dort diskutieren sie die Möglichkeit, Tor-Benutzern Inhalte aus dem Netzwerk bereitzustellen. Ich denke, dass dies ein wirklich interessanter Ansatz ist, und ich bin gespannt darauf, ihn in Zukunft weiter zu erforschen.
WebDriver ist ein leistungsstarkes Tool zum Testen und kann auch zum Sammeln von Informationen an Orten verwendet werden, an denen der Zugriff auf eine API nicht möglich ist. Zum Beispiel: Der Zugang ist anderweitig eingeschränkt, zensiert, zu teuer oder wird generell durch wettbewerbswidrige Praktiken blockiert. Noch besser ist es, die beim Webcrawlen gesammelten Daten mit den von APIs gesammelten Informationen zu kombinieren.
Dies ist eine wichtige Übung, da es immer schwieriger wird, böswilligen Datenverkehr von Bots zu verhindern, und es keine gute Sicherheitspraxis ist, zu warten, bis ein Angriff auftritt, um darüber nachzudenken, wie man ihn entschärfen kann. Meiner Meinung nach sollte jeder, der für die Online-Veröffentlichung von Informationen verantwortlich ist, wissen, wie verletzte Informationen gegen die Systeme verwendet werden, für die er verantwortlich ist. In einem vereinfachten Szenario mit ethischen Einschränkungen habe ich dies wie folgt demonstriert: