Wie man jede Art von Eingabeformular absichert


In diesem Beitrag zeigen wir, wie Sie jedes Kontaktformular oder jede andere Art von Eingabeformular auf Ihrer Website schützen können. Der folgende Ansatz funktioniert als Drop-in-Lösung für statische Websites und für Webhosts mit eingeschränkten Funktionen. Die einzige Voraussetzung ist, dass Sie Schreibzugriff auf den HTML-Code der Website haben.

Nicht jede Website basiert auf einer voll ausgestatteten Blogging-Software, einem Content-Management-System oder einer anderen Art von Webanwendung. Tatsächlich sind viele kleinere Seiten und Blogs sogenannte statische Webseiten, die manuell, manchmal mit Hilfe von Website-Generatoren, erstellt werden. Solche Seiten sind leicht zu warten und benötigen keine speziellen Funktionen auf dem Webhost. Dennoch können auch hier Kontaktformulare, Kommentarfunktionen oder andere interaktive Elemente vorhanden sein, die ggfs. geschützt werden müssen. Mit Hilfe von Hexis API können verletztende Nachrichten automatisch erkannt, blockiert, und den Autoren umgehend eine Fehlermeldung angezeigt werden – alles in Echtzeit.

Dieser Beitrag enthält zwei Rezepte, die zeigen, wie Hexis API in eine beliebige Webseite integriert werden kann.

  • Rezept #1 wird auf der Client-Seite nur unter Verwendung von Vanilla-Javascript implementiert (keine Frameworks erforderlich).
  • Rezept #2 erweitert diesen Ansatz mit einem kleinen PHP-Skript für zusätzliche Sicherheit.

Diese Lösungen funktionieren sowohl für statische Webseiten, als auch für jede andere Art von Webseite oder Webanwendung, die eine schnelle Lösung zum Schutz ihrer Eingabeformulare benötigt.

Hinweis: Wenn Sie noch keinen Hexis API-Schlüssel haben, gehen Sie zu Ihrem Konto und erstellen Sie kostenlos einen.

Rezept #1: Client-seitig

Fügen Sie das folgende Skript in den head der HTML-Datei ein:

<script>    
  window.onload = function(){
    var API_URL = 'https://api.hexis.ai/mod-1/en';
    var API_KEY = 'Ihr API-Schlüssel';
    var FIELD_ID = 'ID des Input-Elementes';
    var FORM_ID = 'ID der Input-Form';
    var THRESHOLD = 0.9;
    var STOP_MESSAGE = 'Bitte formulieren Sie Ihren Kommentar neu. Es sieht so aus, als würde Ihr Kommentar wahrscheinlich als unhöflich oder respektlos interpretiert werden.';
    var ERROR_MESSAGE = 'Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.';

    form = document.getElementById(FORM_ID)
    form.addEventListener('submit', event => {
      event.preventDefault();
      var data = JSON.stringify({'text': document.getElementById(FIELD_ID).value});
      var xhr = new XMLHttpRequest();
      xhr.open('POST', API_URL, true);
      xhr.setRequestHeader('Authorization', 'Bearer '+API_KEY);
      xhr.onload = function () {
        var res = JSON.parse(this.response);
        if (res.scores != null) {
          if (res.scores[0] > THRESHOLD) {
            alert(STOP_MESSAGE);
          } else {
            form.submit();
          }
        } else {
          alert(ERROR_MESSAGE);
        }
      };
      xhr.send(data);
    })
  }
</script>

Zu Beginn dieser Funktion müssen ein paar Konstanten definiert werden.

  • Geben Sie Ihren API_KEY ein.
  • Setzen Sie FIELD_ID mit der ID des Input-Elementes, in das die Textnachricht geschrieben werden.
  • Setzen Sie FORM_ID mit der ID des direkt übergeordneten form-Elementes.

Das ist alles.

Der Wert THRESHOLD ist mit 0.9 relativ hoch angesetzt. Das liegt daran, dass wir in diesem Beispiel jene Nachrichten, die den Wert überschreiten, sofort ablehnen werden. Wir wollen daher nicht, dass das System übermäßig empfindlich ist. Natürlich kann dieser Wert abhängig von Ihrem Anwendungsfall eingestellt werden. Weitere Informationen finden Sie in der [Dokumentation] (https://hexis.ai/de/docs#section/Using-the-API/Classification-Score).

Diese Art Informationen mit der API auszutauschen impliziert, dass die API-Schlüssel im Quellcode Ihrer Webseite aufscheinen – was für kleinere Anwendungsfälle an sich kein Problem darstellt. Der API-Zugriff muss jedoch mit Hilfe der Client-Einschränkungen in Ihren Kontoeinstellungen beschränkt und nur Ihre Webseite zugelassen werden.

Geben Sie die vollständige URL-Adresse Ihrer Webseite (einschließlich http://) in das Feld Allow Referrer URL ein.

Testen Sie den Schutz Ihres Eingabeformulars und die folgende Fehlermeldung wird angezeigt.

Gut gemacht, es kommen keine schädlichen Nachrichten mehr durch Ihre Eingabeform!

Rezept #2: Client- und Server-seitig

Der folgende Code funktioniert als Drop-In-Lösung auf Webhosts, die PHP unterstützen. Die meisten modernen Webserver unterstützen es standardmäßig. Warum sollten wir die Funktionalität zwischen einer Client- und einer Server-Seite aufteilen wollen? Alles, was auf der Client-Seite ausgeführt wird, muss öffentlich erreichbar sein. Für zusätzliche Sicherheit wollen wir den API-Schlüssel in einem serverseitigen Skript speichern und auch die API-Anfrage von dort aus stellen.

Fügen Sie zunächst das folgende Skript in den head der HTML-Datei ein:

<script>
  window.onload = function(){
    var PHP_URL = 'api.php';
    var FIELD_ID = 'ID des Input-Elementes';
    var FORM_ID = 'ID der Input-Form';
    var THRESHOLD = 0.9;
    var STOP_MESSAGE = 'Bitte formulieren Sie Ihren Kommentar neu. Es sieht so aus, als würde Ihr Kommentar wahrscheinlich als unhöflich oder respektlos interpretiert werden.';
    var ERROR_MESSAGE = 'Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.';

    form = document.getElementById(FORM_ID)
    form.addEventListener('submit', event => {
      event.preventDefault();
      var data = new FormData();
      data.append('text', document.getElementById(FIELD_ID).value);
      var xhr = new XMLHttpRequest();
      xhr.open('POST', PHP_URL, true);
      xhr.onload = function () {
        var res = JSON.parse(this.response);
        if (res.status && res.score != null) {
          if (res.score > THRESHOLD) {
            alert(STOP_MESSAGE);
          } else {
            form.submit();
          }
        } else {
          alert(ERROR_MESSAGE);
        }
      };
      xhr.send(data);
    })
  }
</script>

Zu Beginn dieser Funktion müssen die folgenden Konstanten definiert werden.

  • Setzen Sie FIELD_ID mit der ID des Input-Elementes, in das die Textnachricht geschrieben werden.
  • Setzen Sie FORM_ID mit der ID des direkt übergeordneten form-Elementes.

Diese Funktion führt im Grunde den gleichen Remote-Aufruf aus wie in Rezept #1, aber dieses Mal POSTen wir auf ein PHP-Skript, anstatt direkt an die API zu posten.

Als nächstes erstellen wir die Datei api.php, die den folgenden Code enthält:

<?php

// constants
$API_URL = 'https://api.hexis.ai/mod-1/en/v1';
$API_KEY = 'Ihr API-Schlüssel';
$FORM_URL = 'https://your.domain/form.html';

// submit to api
function classify ($text) {
  global $API_URL, $API_KEY;
  $postData = json_encode(array('text' => $text));
  $ch = curl_init($API_URL);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer '.$API_KEY, 'Content-Length: '.strlen($postData)));
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $response = curl_exec($ch);
  curl_close($ch);
  return $response;
}

if ($_POST['text'] != '' and $_SERVER['HTTP_REFERER'] == $FORM_URL and $_SERVER['HTTP_ACCEPT_LANGUAGE'] != '' and strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false) {
  $result = json_decode(classify($_POST['text']));
  echo json_encode(array('status' => $result ? 1 : 0, 'score' => $result ? $result->scores[0] : 'An error has occured'));
}

?>

Hier müssen die folgenden Konstanten definiert werden.

  • Geben Sie Ihren API_KEY ein.
  • Ändern Sie FORM_URL in die vollständige URL-Adresse der HTML-Datei (einschließlich http://).

Anschließend muss das PHP-Skript in seinen Dateiberechtigungen als ausführbar gesetzt werden (abhängig von Ihrem Webhost – in einer UNIX-Umgebung sind die Berechtigungen 755. Auf der Kommandozeile: chmod 755 api.php).

Sicherheitsfragen

In Anbetracht der sicherheitsrelevanten Auswirkungen unserer Codeschnipsel ist das Szenario, um das wir uns kümmern, dieses: Wie schützen wir ein öffentliches Eingabeformular vor Missbrauch durch automatisierte Clients?

Die Verwendung eines öffentlichen API-Schlüssels zusammen mit anderen Mitteln der Zugriffskontrolle (wie in Rezept Nr. 1) ist durchaus praktikabel. Es ist jedoch zu beachten, dass HTTP_REFERER innerhalb des Anfrage-Headers gefälscht sein kann, so dass in diesem Fall unsere Sicherheit davon abhängt, dass der Angreifer nichts von der referer-basierten Zugriffsbeschränkung weiß. Dies ist nicht die sicherste, aber die am einfachsten zu implementierende Maßnahme.

Eine bessere Lösung ist die Verwendung eines serverseitigen Skripts, das die API-Anforderung ausführt und dessen Quellcode für den Client nicht zugänglich ist (wie in Rezept Nr. 2). Die Sicherheit hängt in diesem Fall davon ab, sicherzustellen, dass nur unsere HTML-Datei an das PHP-Skript POSTen kann. Um dies zu erreichen, wollen wir sicherstellen, dass der POST von einem echten Web-Browser kommt. Dann können wir die Tatsache ausnutzen, dass die Änderung des HTTP_REFERERER einer AJAX-Anfrage vom Browser verhindert wird. Wir haben dies durch Überprüfung der HTTP_ACCEPT_LANGUAGE und CONTENT_TYPE Header-Werte implementiert, aber Sie können jederzeit weitere Werte ausprobieren oder – besser noch – kombinieren Sie diesen Ansatz mit einem CAPTCHA, der sicherstellt, dass nur ein Mensch das Formular abschicken kann.

PS: Der beste Ansatz, falls Sie ein Webanwendungs-Framework und eine Datenbank verwenden: Sie können den Schutz vor automatisierten Clients als ein Rate Limiting-Problem behandeln. Vermerken Sie einfach alle Client-IPs und legen Sie ein Limit fest, wie oft ein Client innerhalb eines bestimmten Zeitrahmens einen Antrag stellen darf.