Spambot Bekämpfung ohne Captcha Abfrage

Kontaktformulare sind ein guter Weg Besucher der eigenen Website oder des eigenen Blogs die Möglichkeit zu geben Kontakt aufzunehmen. Seit jeher sind aber auch Bots daran interessiert unerwünschte Werbung über diese Kanäle abzuschicken. Der große Vorteil von Kontaktformularen ist für Spammer, dass die aus dem Formular resultierende Mail mit großer Wahrscheinlichkeit auch wirklich gelesen wird. Mittlerweile gibt es diverse Lösungsansätze um Bots davon abzuhalten, Formulare auf der eigenen Website ausfüllen zu können. Eine der bekannteren Lösungen ist z.B. eine Sicherheitsfrage oder Google’s reCaptcha das dem Nutzer von Zeit zu Zeit Bilderrätsel zeigt die ausgefüllt werden wollen. Beide Lösungen sind für echte Website Besucher nicht optimal und können schnell zu einem Störfaktor werden. Im Fall von reCaptcha spielt auch das Thema Datenschutz eine Rolle. Die Daten die Google aus dem Formular erhebt sind aus technischer Sicht zwar nur auf das Captcha beschränkt, ganz ohne Bauchweh bleibt die Verwendung aber trotzdem nicht. Man sollte davon ausgehen, dass Google Userdaten wie die IP-Adresse, das Nutzerverhalten sowie Browserdetails aufzeichnet. Ohne passenden Datenschutzhinweis kann die Verwendung also problematisch werden. Abseits von Captcha’s und Sicherheitsfragen gibt es aber noch weitere Möglichkeiten Bots erfolgreich auszusperren.

Was machen Spambots eigentlich?

Bevor wir an die Lösungsansätze ansehen, zuerst ein paar interessante Informationen über die Funktionsweise der meisten Bots. Bei Bots handelt es sich im Grunde um Scripts die automatisiert das Internet nach Websites durchsuchen und auf eben diesen Zielgerichtet auf die Suche nach Formularen, E-Mail Adressen sowie anderen Informationen gehen. Dabei springt der Spambot von Seite zu Seite indem er die Links auf der Seite weiterverfolgt. Der Google Spider macht im Grunde nichts anderes, er besucht eine Seite, analysiert den Inhalt, sendet Informationen an die Google Server und springt anschließend von Seite zu Seite. Der große Unterschied zwischen Bots von z.B. Google und Spammern, ist das Verhalten im Bezug auf Formulare. Google Bots füllen keine Formulare aus, Spambots lieben Formulare.

Vorteile von Spambots 

Spambots sind auf Geschwindigkeit getrimmt und versuchen gleichzeitig so wenig Ressourcen wie möglich zu Verbrauchen. Für Spammer gilt Masse statt Klasse und Zeit ist Geld. Der Betrieb eines Spamservers kostet Geld und die abgesendeten Spams haben in den meisten Fällen nur wenig Erfolgschancen. Ziel ist es also so viele Spamnachrichten wie möglich abzuschicken. Pro Server laufen gleichzeitig eine Vielzahl an Bot-Instanzen die gleichzeitig das Internet durchstöbern. Um mehr Bots pro Server ausführen zu können, nutzen Bots einfache Anfragen die an Webserver geschickt werden. Der zurückgegebene HTML Code wird anschließend analysiert. Mitgelieferter CSS oder JavaScript Code wird meist nicht interpretiert um Ressourcen und Zeit zu sparen.

Ansätze zur Spambot Bekämpfung

Wir wissen also ungefähr wie Spambots funktionieren und welche Ziele die Bots verfolgen. Ein Bot der auf die eigene Website kommt, durchforstet alle Unterseiten, stoppt bei jedem gefundenen Formular und versucht dieses auszufüllen und abzuschicken. Wir können davon ausgehen, dass ein großteils der Bots dabei Dinge wie CSS und JavaScript ignorieren. Dieser Umstand, der auch als Vorteil von Spambots interpretiert werden kann, kann zu unserem Vorteil genutzt werden.

Honeypots

Als Honeypot bezeichnet man einen Bereich der eigenen Website die für normale Besucher unsichtbar bzw. unkenntlich gemacht werden. In unserem Fall werden wir einen Honeypot in Form eines Eingabefelds in unser Formular einbauen. Per CSS oder auf Wunsch auch per JavaScript wird dieses Feld anschließend ausgeblendet. Spambots die unsere Seite besuchen und das Kontaktformular finden, sehen den Honeypot als normales Eingabefeld und sind verleitet diesen Auszufüllen. Bei der Verarbeitung des Formulars reicht anschließend eine kurze Abfrage ob das Honeypot Eingabefeld ausgefüllt wurde um mit ziemlicher Sicherheit davon ausgehen zu können, dass die Anfrage von einem Roboter abgeschickt wurde.

Timestamps

Ein normaler Besucher benötigt eine minimale bzw. maximale Zeit um ein Kontaktformular oder Kommentar-Formular auszufüllen. Man kann ohne weiteres davon ausgehen, dass mindestens 10 Sekunden zwischen dem Besuch der Seite und dem abschicken des Formulars vergehen. Bots können diese Arbeit in wenigen Sekunden erledigen. Wir müssen also nur herausfinden wie viel Zeit zwischen dem Seitenaufbau und dem abschicken des Formulars vergangen ist um mögliche Bots zu identifizieren.

Bots die unsere Seite besuchen und Formulare abschicken möchten, müssen mit diesen Änderungen zuerst an dem Honeypot-Feld vorbei und das ausgefüllte Formular anschließend zum richtigen Zeitpunkt abschicken.

Umsetzung mit PHP, HTML und CSS

Werfen wir zuerst einen Blick auf unser HTML Formular mit passenden Hintergrundinfos zu den jeweiligen Feldern.

				
					    <form action="contact.php" method="POST">
      <!-- # Felder die durch User ausgefüllt werden -->
      <div class="formfield">
        <label for="name">Name:</label>
        <input type="text" name="name">
      </div>
      <div class="formfield">
        <label for="email">E-Mail:</label>
        <input type="email" name="email">
      </div>
      <div class="formfield">
        <label for="message">Ihre Nachricht</label>
        <textarea name="message"></textarea>
      </div>


      <!-- Sicherheitsfelder
        Im Nonce Feld wird ein zuvor erstellter "Fingerabdruck" abgespeichert
        der später im Actions Controller geprüft wird. Die Nonce auch CSRF oder
        anders genannt wird benötigt um Cross Scripting Angriffe zu erschweren.
        CMS Systeme wie WordPress oder Frameworks wie Laravel haben passende Funktionen
        zur Einbindung dieser Felder sowie zur Überprüfung. In diesem Beispielt dient das Feld
        nur um euch darauf aufmerksam zu machen diese Funktionen unbedingt zu verwenden.
      -->
        <input type="hidden" name="nonce" value="publicsecret1">


      <!-- Honeypot Feld
        Spam Bots suchen in Formularfeldern nach bekannten Bezeichnungen um einzelne Felder
        voneinander unterscheiden zu können. So gut wie jeder Bot kann dabei zwischen
        den verschiedenen Arten an Textfeldern unterscheiden. Ist ein Textfeld als hidden
        markiert werden sie von Bots ignoriert. Aus diesem Grund erhält unser Honeypot Feld
        per CSS den Wert "display:none;". Dies verhindert das der Browser dem Besucher das Feld
        anzeigt, einfache Bots gehen davon aus, dass das Feld sichtbar ist. Zusätzlich erhält
        das Feld den ansprechenden Namen "subject". Sollte unser "subject" Feld bei der späteren
        Prüfung ausgefüllt sein, können wir die Anfrage direkt blockieren.

        Nachtrag: Ausgefeiltere Bots können über CSS ausgeblendete Elemente erkennen und
        uns nicht in die Falle gehen.
      -->
      <input type="text" class="noeyes" name="subject" value="">


      <!-- Timer Feld
        Für Spammer ist Zeit Geld. Ein Bot hält sich auf jeder Seite also nicht lange
        auf bevor er zur nächsten Seite weiterspringt. Die benötigten Informationen
        werden abgerufen und sofern sich ein Kontaktformular oder ein anderes Ziel
        auf einer Seite befindet, wird dieses angegriffen.
        Die Zeit die ein Bot benötigt um ein Formular auszufüllen liegt oft unter einer Sekunde.
        Diesen Umstand können wir zu unserem Vorteil nutzen. Im Timer Feld platzieren wir
        einen kodierten Timestamp der bei der Abfrage der Seite generiert wird.
        Während der Validierung des Formulars prüfen wir den Timer um zu sehen wie schnell das
        Formular ausgefüllt und abgeschickt wurde. Formulare die in weniger als 5 Sekunden
        ausgefüllt und abgeschickt wurden können wir anschließend mit ziemlicher Sicherheit blockieren.

      -->
      <input type="text" class="noeyes" name="phone" value="<?php echo generateTimeHash($key, $cipher, $iv); ?>">

      <input type="submit" value="Absenden">

    </form>
				
			

Im Beispiel haben wir zuerst unsere normalen Eingabefelder für Name, E-Mail, und die Nachricht die abgeschickt werden soll. Anschließend habe ich zu Demo-Zwecken ein sogenanntes Nonce-Feld eingebaut. Die „Nonce“ soll Cross-Site-Request-Forgery Angriffe abwehren und sollte in jedem Formular auf eurer Seite genutzt werden. Praktisch alle CMS-Systeme sowie Frameworks bieten diese Funktion und sollten auf jeden Fall genutzt werden. In der Demo sind die Felder zwar eingetragen aber nicht mit Funktionen versehen.

Interessant wird das Form-Feld beim nächsten Input-Feld mit dem Namen „subject“. Bei diesem Feld handelt es sich um unser Honeypot Feld. Der Name des Formfelds ist so gewählt, dass er für mögliche Bots als Betreff-Feld registriert und passend ausgefüllt wird. Per CSS wird das Formfeld ausgeblendet und ist somit für normale Besucher nicht sichtbar. Wir blenden das Feld per CSS aus, da Bots Formfelder vom Typ „hidden“ ignorieren würden.

Nach unserem Honeypot-Feld findet sich unser Timer. Im Timer Feld platzieren wir eine verschlüsselte Timestamp die bei der Erstellung der Seite per PHP generiert und eingefügt wird. Dieses Feld blenden wir auch per CSS aus und geben ihm einen für Bots interessanten Namen um Änderungen an dem Feld zu provozieren. In unserer contact.php Datei die Anfragen verarbeitet wird dieses Feld anschließend entschlüsselt und geprüft. Natürlich prüfen wir bei der Gelegenheit auch gleich, ob ein Bot Änderungen an dem Feld vorgenommen hat.

Nachfolgend die Funktion die für die Erstellung des verschlüsselten Timestamps zuständig ist.

				
					// der Key mit dem wir unser timer feld verschlüsseln
$key = 'MySecretHashkey876574';

// zweiter unique key für die verschlüsselung und entschlüsselung des timehash
$iv = '0259847523614897';

// die verschlüsselungsmethode
$cipher = 'aes-128-cbc';


// erstellt verschlüsseltes timestamp feld
function generateTimeHash($key, $cipher, $iv) {

  // erstelle aktuellen timestamp
  $time = new DateTime();

  // teste ob verschlüsselungsmethode vorhanden ist oder stirb
  if(in_array($cipher, openssl_get_cipher_methods())) {

    // gibt verschlüsselten timestamp wert zurück
    return openssl_encrypt($time->getTimestamp(), $cipher, $key, 0, $iv);

  }

  die('Verschlüsselungsmethode nicht gefunden oder Fehler bei Verschlüsselung');

}
				
			

Für die Verschlüsselung des Timestamp Felds nutzen wir die PHP-Funktion openssl_encrypt. Dieser übergeben wir den aktuellen Timestamp, die Verschlüsselungsmethode, einen Schlüssel sowie einen Initialisierungsvektor. Die Funktion testet auch ob die gewählte Verschlüsselungsmethode verfügbar ist und beendet das Script falls dem nicht der Fall ist. Das Timestamp Feld sieht im fertigen Formular anschließend wie folgt aus.

Kommen wir zur contact.php in der wir die erhaltene Anfrage bearbeiten. Starten wir mit unserem Honeypot-Feld. Wie zuvor beschrieben muss dieses Feld leer sein, falls es ausgefüllt ist, handelt es sich bei der Anfrage höchstwahrscheinlich um einen Bot. Wir testen ob die POST Variable vorhanden ist und ob sie wie erwartet ein leerer String ist. In der Demo beenden wir die Ausführung sofern das subject Feld nicht übergeben wurde.

				
					$honeypot = isset($_POST['subject']) ? $_POST['subject'] : die('Betreff Feld gelöscht');


/*
  Wenn das Honeypot Feld nicht leer ist, gehen wir davon aus das uns ein Bot
  in die Falle gegangen ist.
*/
if(!empty($honeypot)) {
  $failmessage = true;
}
				
			

Im nächsten Schritt kümmern wir uns um unsere Timestamp Variable. Diese muss uns übergeben werden und auch erfolgreich entschlüsselt werden können. Sollte die Entschlüsselung nicht funktionieren wurde das Eingabefeld bearbeitet. Dies bedeutet, dass der Bot oder der User auf der anderen Seite unerwünschte Absichten hat. Die Anfrage wird also blockiert. Sollte das Timestamp Feld entschlüsselt werden können vergleichen wir die aktuelle Zeit mit der übergebenen Zeit und ermitteln die vergangenen Sekunden mit unseren minimalen und maximalen Werten.

				
					/* Minimale Zeit in Sekunden die nach der Auslieferung der Seite
  vergehen muss um nicht im Botfilter zu landen
*/
$minTime = 5;

/* Maximale Zeit in Sekunden die während des ausfüllens des Formulars verstreichen darf
  manche bots befüllen das Formular und senden es zu einem späteren Zeitpunkt ab um diese
  Art der Sicherheitschecks zu umgehen.
*/
$maxTime = 3600;

$givenTime = isset($_POST['phone']) ? $_POST['phone'] : die('Timestamp Feld gelöscht');

// dekodiere übergebenen Timestamp
$decryptedTime = openssl_decrypt($givenTime, $cipher, $key, 0, $iv);

// überprüfe ob der übergeben wert überprüft werden konnte
if($decryptedTime) {

  // erstelle aktuellen timestamp
  $currentTime = new DateTime();
  $currentTime = $currentTime->getTimestamp();

  /*
    Jetzt berechnen wir die Sekunden die der User für das Ausfüllen des Formulars
    benötigt hat. Sollte der Wert kleiner als unser Threshold sein, blockieren wir
    die Anfrage.
  */
  if( ($currentTime - $decryptedTime) <= $minTime || ($currentTime - $decryptedTime) >= $maxTime ) {
    $failmessage = true;
    $timeError = 'Minimale Zeit für Ausfüllung unterschritten / überschritten';
  }

} else {
  // gelieferter Wert konnte nicht decypted werden -> Eingabefeld wurde bearbeitet
  $failmessage = true;
  $timeError = 'Verschlüsselter Zeit-String wurde bearbeitet';
}
				
			

Sollte die $failmessage Variable nach der Ausführung True sein, stehen die Chancen gut, dass die Anfrage von einem Bot ausgegangen ist. Die Variable $honeypot beinhaltet den Text der in unser Honeypot Feld eingegeben wurde, oder ist leer wenn die Variable nicht ausgefüllt wurde. Die Variable $timeError wird auf true gesetzt wenn es ein Problem bei der Entschlüsselung der übergebenen Daten gegeben hat, oder wenn die vergangene Zeit nicht die Schwellenwerte erreicht, oder diese überschritten hat. Zum Abschluss noch die Ausgabe der contact.php in unserer Demo.

				
					<?php
/*
  In dieser Demo werden die POST Variablen nicht gefiltert und validiert!
*/
$name = $_POST['name'];
$email = $_POST['email'];
$message = $_POST['message'];

?>


<html>
  <head></head>
  <body>
    <p>
      <?php if( $failmessage ) {
        echo '<span style="color:red;font-weight:bold;">Bot Aktivität entdeckt</span>';
      } else {
        echo '<span style="color:green;font-weight:bold;">Keine Bot Aktivität entdeckt</span>';
      }
      ?>
    </p>
    <p>
      Ihr Name: <?php echo $_POST['name']; ?><br>
      Ihre E-Mail: <?php echo $_POST['email'];?><br>
      Ihre Nachricht: <?php echo $_POST['message']; ?>
    </p>
    <p>
    Honeypot: 
    <?php 
    if(!empty($honeypot)) {
      echo '<span style="color:red;font-weight:bold;">ausgefüllt</span><br> ';
      echo 'Eingegebener Text: ' . $honeypot;
    } else {
      echo '<span style="color:green;font-weight:bold;">nicht ausgefüllt</span>';
    } ?>
    <p>
    <p>
      Zeitfeld:
      <?php if( !$timeError ) {
        echo '<span style="color:green;font-weight:bold;">Vergange Zeit in Sekunden:' . ($currentTime - $decryptedTime) . '</span>';
      } else {
        echo '<span style="color:red;font-weight:bold;">' . $timeError . '</span>';
      }?>
    </p>
  </body>
</html>
				
			

Alle Daten aus der Demo die für diesen Beitrag erstellt wurde habe ich in dieser .zip Datei für euch bereitgestellt. Download

Fazit

Einfach gestrickte Bots können mit diesen ersten Maßnahmen schnell ausgesperrt werden. Ein Vorteil dieser Maßnahmen ist, dass echte Besucher nichts von den Maßnahmen zu spüren bekommen. Was in unserer Demo fehlt ist weitere Logik die mögliche Angreifer nach mehreren Versuchen aussperrt. Denkar ist eine zeitliche Sperre oder eine Blacklist. Die rechtlich Tragbarkeit einer Blacklist unter der DSGVO ist leider bedenklich. Möglich ist es auch dem Bot eine erfolgreiche Anfrage vorzugaukeln im Hintergrund aber keine Aktionen auszuführen. Möglich wäre es an dieser Stelle auch dem Bot eine 404 Fehlerseite zu zeigen und ihm vorzugaukeln, dass das Formular ins nichts führt.

Intelligentere Bots die Formulare z.B. zeitversetzt abschicken und auch CSS oder JavaScript auslesen können, werden durch die oben gezeigten Maßnahmen leider wenig beeindruckt. Mögliche weitere Absicherungen wäre z.B. die Nutzung eines einmaligen Tokens der in der Session jedes Besuchers gespeichert und bei der Verarbeitung des Formulars abgefragt und getestet wird. Sollten alle Stricke reißen kann man in letzter Instanz natürlich immer noch eine Sicherheitsabfrage einbauen.

Solltet Ihr weitere Tipps für den Kampf gegen Formular-Spam auf der eigenen Website haben, könnt Ihr diese gerne in den Kommentaren hinterlassen.

Gerne helfe ich auch bei der Umsetzung von Lösungen gegen Spam. Kontaktiert mich, oder erfahrt mehr über meine weiteren Angebote bei der Website Erstellung.

Kontakt
Ihre Daten werden ausschließlich zur Bearbeitung Ihrer Anfrage verarbeitet. Mehr Informationen findest du in unserer Datenschutzerklärung

Bürozeiten:
Montag – Donnerstag: 9:00 – 17:00 Uhr
Freitag: 9:00 – 14:00 Uhr