⬅ Zurück zur Übersicht

SPAM protection methods N° 1: Honeypot

david am Sonntag, 13.05.2018 - 16:57:17
⬅ Zurück zur Übersicht

Ein leidiges Thema seit Anbeginn des Internets ist SPAM (nein, nicht das Dosenfleisch, das gibt es länger als das Internet).

An einem gelangweilten Wochenende hatte ich mir mal ein paar Gedanken darüber gemacht, wie wir SPAM (alternativ auch: Webcrawler) vermeiden können, und daraus entstand die Reihe „SPAM protection methods“.
Teil 1 dieser Reihe handelt vom Aussperren nerviger SPAM Bots von unserer Webseite, kann aber auch genutzt werden um automatisierte Tools wie SiteSucker, aber auch automatisierte Skripte via Chromium o.ä. fernzuhalten.
Wie immer gilt – und hier ganz besonders: Der Beitrag dient nur als Anregung und sollte nicht unüberlegt 1:1 kopiert werden. Bei falscher Anwendung kann das Skript dazu führen, dass reguläre Nutzer von der Seite ausgesperrt werden (z.B. dann, wenn Sie einen Content – Preloader verwenden oder gar der Browser selbst den Inhalt vorlädt)

1. Konzept

Grundsätzlich wollen wir im ersten Schritt den Bot erkennen und im zweiten Schritt blockieren.
Meine ursprüngliche Idee war, den Bot über die htaccess Datei zu blockieren. Sobald unser Skript einen Bot erkennt, sollte er ans Ende der htaccess Datei die Zeile

1
deny {IP}

schreiben und so den Bot bzw. dessen IP – Adresse von unserer Seite aussperren.

Idee gut, Umsetzung problematisch: Als ich gemerkt hatte, dass das voraussetzt, dass ich die .htaccess – Datei mit chmod beschreibbar mache, ist mein Puls seltsamerweise auf einen Bereich um 200 gestiegen 🔥🔥🔥. Eine Alternative musste her, und diese lautet „Sessions“. Wir speichern ganz einfach den Status des Nutzers in der Session und die geblockten IP – Adressen in einer Datenbank. Immer wenn ein neuer Nutzer auf die Seite kommt schauen wir in der Datenbank nach, ob seine IP – Adresse geblockt ist. Je nach dem bekommt er dann eine Session Variable zugewiesen die wir bei jedem Seitenaufruf prüfen können und uns somit einige SQL – Abfragen sparen. Achtung: Nur Sessions reichen natürlich nicht. Sonst hilft ein einfacher Cookiedelete.
Problematischer ist es jedoch, überhaupt zu erkennen ob es sich um einen Bot oder nicht handelt.
Meine Lösung war bisher lediglich, einen „hidden Link“ einzufügen in der Form

1
<a href='https://example.com/target.php' style='display:none;'>Ultra Fancy Link</a>

Ein Spambot, welcher nicht erkennen kann, ob der Link wirklich sichtbar ist oder nicht (da für ihn nur das href – Attribut relevant ist, nicht der style – tag) ruft er die target.php auf, in welcher sich unser honeypot befindet.

Allerdings führte das dazu, dass Browser oder Plugins, welche den Content teilweise precachen, die Seite ebenfalls aufrufen und somit auch ein „normaler“ Nutzer in unseren Honeypot geraten kann. Und das gilt es natürlich zu 100000000% zu vermeiden ☠.

Das Problem konnte ich relativ einfach umgehen, indem ich den Pfad https://example.com/target.php in die robots.txt geschrieben habe. Offensichtlich beachten Browser, welche Content precachen die robots.txt (zumindest die Guten) und so lässt sich ein „false positive“ vermeiden.
Die target.php macht jetzt nichts anderes, als die Datenbank mit der IP Adresse des Browsers zu füttern.

2. Umsetzung

Schritt 1: Datenbank

Als erstes erstellen wir die Tabellen in der Datenbank:

1
2
3
4
5
6
CREATE TABLE `spamblock` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`ip` text,
`stamp` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

die Tabelle Spamblock enthält jetzt die obligatorische primary ID, ein Feld „ip“ in das Später die IP – Adresse eingetragen wird als auch „stamp“, welches später den timestamp enthalten soll.

Schritt 2: target.php

Als nächstes ist die target.php dran (diese könnt ihr selbstverständlich auch anders nennen)
Diese fügt einmal die IP – Adresse und den Timestamp in unsere Tabelle ein und setzt die Session – Variable.

1
2
3
4
5
6
7
8
9
10
11
<?php
session_start();
$_SESSION['spamblock'] = true;
$dbh = new PDO('mysql:host=localhost;dbname=TEST', 'USERNAME', 'PASSWORD');
$stmt = $dbh->prepare("INSERT INTO spamblocked (ip, stamp) VALUES (:ip, :stamp)");
$stmt -> bindParam(':ip', $ip);
$stmt -> bindParam(':stamp', $stamp);
$ip = $_SERVER['REMOTE_ADDR'];
$stamp = time();
$stmt -> execute();
?>

Natürlich müssen hier dbname, username und password durch eure Daten ersetzt werden.

Schritt 3: Überprüfung der Variable

Bei jedem Seitenaufruf muss jetzt überprüft werden, ob $_SESSION[’spamblock‘] true oder false ist.
Entweder wir auto prependen jetzt das folgende Skript via htaccess:

1
php_value auto_prepend_file "/var/www/virtual/david/check.php"

(Achtung: Absoluter Pfad!)
oder wir fügen folgende Zeile an den Anfang jeder Seite:

1
2
3
4
&lt;?php
session_start()
if (isset($_SESSION['spamblock']) &amp;&amp;$_SESSION['spamblock'] === true) die();
?&gt;

Hiermit prüfen wir, ob die Variable $_SESSION[’spamblock‘] gesetzt ist und den Wert true enthält. Wenn
ja, beenden wir das Skript.

Schritt 4: Robots.txt

Als nächstes fügen wir die target.php in unsere robots.txt ein, damit wir auch keine „guten“ Crawler verschrecken und keine Probleme mit precaching bekommen.

1
2
User-agent: *
Disallow: /target.php

Der Aufbau der robots.txt sollte selbsterklärend sein.

Schritt 5: Hidden Link oder sonstige Weiterleitung

Als letzten Schritt fügen wir den hidden link in unsere reguläre Seite ein, am besten so weit „vorne“ wie möglich (index.php ist gut, /unterseite/unterseite/unterseite/irgendeinfile.php ist schlecht). Denn wenn der Crawler die ganze Seite abgearbeitet hat und erst am Ende ausgesperrt wird, nachdem er seine Arbeit verrichtet hat, macht das ganze keinen Sinn mehr). Alternativ kann man auch eine Weiterleitung per Javascript machen.
Möglichkeit eins wäre der o.g. „display:none“ attribute bei einem Link.

1
&lt;a href='target.php' style='display:none'&gt;

Möglichkeit zwei wäre Javascript, was allerdings voraussetzt, dass der Crawler Javascript deaktiviert hat (Und Achtung: Sobald ein regulärer Nutzer kein Javascript aktiviert hat, wird er ebenfalls ausgesperrt. Das hier soll also eher ein Denkanstoß sein als eine ernsthafte Lösung)

1
2
3
&lt;noscript&gt;
&lt;iframe src="target.php"&gt;&lt;/iframe&gt;
&lt;/noscript&gt;

Sicherlich lässt sich das ganze noch erweitern. Wenn ihr Ideen habt, gerne in die Kommentare hauen.

Schritt 6: Abschließen

Schlussendlich laden wir alle Dateien hoch, bereiten die Datenbank vor und haben im besten Fall in der insert.php die Werte „Username“ und „Password“ bereits mit den Zugangsdaten zu unserer Datenbank ersetzt 😉
 

Ergänzung: adblocker nutzen

Wer noch eins drauf setzen will, kann den adblocker nutzen, den heutzutage fast jeder Nutzer installiert hat, aber wohl kaum ein Crawler.
Wir benennen einfach die Datei target.php in subtarget.php um und schreiben in die target.php folgenden iFrame:

1
&lt;iframe src="subtarget.php" id="advert"&gt;&lt;/iframe&gt;

Bei einem „normalen“ Nutzer sollte jetzt der AdBlocker die Ressource blockieren, während bei einem Bot der iFrame geladen wird und die IP Adresse in die Datenbank geschrieben wird. Statt die id „advert“ zu setzen, können wir die subtarget.php auch einfach advertisting.php nennen – damit sollte Adblock schon aktiv werden.

Kommentar schreiben

Kommentare