Level: mittel

Diese Übung ist ein Best Practice Beispiel für die Herkunftsprüfung von Daten. Es geht darum, ein Script davor zu schützen, aus einem beliebigen Fake-Formular gespiesen zu werden (CSRF Attack) - mit einem Formular-Token. Im Prinzip wird zwischen dem Formular und dem Script ein "Geheimcode" vereinbart, so dass die Formulardaten nur verarbeitet werden, wenn das Formular auch den Geheimcode kennt und mitschickt. Ziel ist, dass in einem verstecken Formularfeld dieser Code mitgeschickt wird, ohne das der Benutzer davon wissen muss.

Aufgabe

  1. Lade die HTML-Vorlage form-token.zip herunter und speichere die enthaltene Datei in deinem Webserver
  2. Du wirst nun oberhalb des formulars in einem PHP Anewisungsblock arbeiten, und eine Session benutzen. Erstelle den Session-Zugriff mit session_start()
  3. Erstelle nun den "Geheimcode", den du in einer Variablen $token speicherst: hierzu kannst du zum Bepspiel die Funktion uniqid() verwenden. Wichtig ist, den zweiten Parameter auf "true" zu setzen, um ein weniger vorhersagbares Ergebnis zu erhalten. Der Code sollte sich ja möglichst nicht erraten lassen: 
    uniqid(mt_rand(), true);
  4. Schreibe dann den Wert aus $token in die Session-Variable unter dem Namen $_SESSION['token'];
  5. Schau dir nun das Formular-HTML an: da ist ein hidden-Field drin, welches einen Hash als String hat. Dieser soll nun durch den von PHP generierten Wert in $token ersetzt werden. Gebe diesen hier als Value aus
  6. Nun ist es Zeit, das Formular zu verarbeiten. Da in der Verarbeitung ebenfalls das Token aus dem Formular mit dem aus der Session verglichen werden wird, MUSS diese Verarbeitung vor dem Teil geschehen, in dem du das Token generiert hast. Frage nun als erstes die Felder des Formulars (Name, Email, Nachricht) mit isset() ab.
  7. Sind diese Felder gemäss isset() Prüfungen alle vorhanden, kannst du da, wo auch die Validierung der einzelnen Felder nun hinkäme, erst das Token vergleichen: vergleiche dazu den Wert aus $_POST mit dem Wert aus $_SESSION. ist er nicht gleich, oder es ist in Formular oder Session kein Token vorhanden, kannst du das Script abbrechen mit die(), indem du die Message "unerlaubter Zugrif!" ausgibst(*).

* Prüft man auf Missbrauch, wird es von manchen Entwicklern bevorzugt, statt einer Fehlermeldung im Layout (mit echo, CSS und HTML) wirklich nur einen Scriptabbruch zu generieren, da mit dieser Methode weniger Bandbreite für die Fehlermeldung benutzt wird. (für den Angreifer keine Bandbreite "verschwenden")

 

Tipps zum Testen

  • Gebe zum Test (ob das Script abgebrochen wurde) noch den erstellten Kommentar aus, z.B. so "Hallo Username, du hast den folgenden Kommentar geschrieben: Kommentartext"
  • Kopiere zum Test (ob die Daten tatsächlich aus deinem Formular stammen) den gesamten HTML-Code des Formulars mitsamt dem Token, welches generiert wurde, aus dem Quellcode in eine andere Datei, und setze im Form-Tag die Action auf dein usprüngliches Script mit dem Formular und der Tokenprüfung. Speichere die Datei als "fake-formular.html" ab. Rufe nun dein Original-Formular noch einmal auf (es wird ein neues Token generiert). So ist zwar im Fake-Formular ein Token drin, aber nicht das gleiche wie in deiner Session. Versende die Daten mal von diesem Formular aus. So verhältst du dich wie ein Hacker, der das Formular missbrauchen (faken) will, und kannst deine Token-Prüfung so testen.

 

Noch nicht genug?

  1. Möchtest du das Formular-Token noch sicherer machen, setzt du ihm auch noch ein Zeitlimit. Hierzu speicherst du noch einen Timestamp in die Session, und prüfst, ob dieser nicht mehr als z.B. 1 Minute zurückliegt. So ist das Zeitfenster für einen Missbrauch etwas kleiner.
  2. Verändere das Token-Feld so, dass nicht der value, sondern der name das Token enthält. Als value kannst du einfach true oder 1 eingeben. Da das name Attribut im POST-Array zum key wird, und uniqid() einen Wert erzeugt, der als Key in einem Array nicht erlaubt ist, mache aus dem generierten Token noch einen Hash, bevor du diesen benützt, z.B. mit md5() oder sha1(). Passe nun auch die überprüfung des Tokens so an, dass sie die Abfrage des name attributs statt des vaues ermöglicht.

    Überlege dir nun: 
    • Wie wirkt sich der Wechsel vom value auf den name auf die Sicherheit des Formulars aus? 
    • Wie wirkt sich dies auf die Überprüfung aus?