rss-icon mail-icon

Portfolio Christian Waldmann

Vom:
Typische Sicherheitslücken in (Php-) Formularen

Blog

Mein "Kompendium" und sonstige Projekte

Typische Sicherheitslücken in (Php-) Formularen

Kontaktformulare sind allgegenwärtig. Gegenüber einer real angegebenen E-Mail-Adresse haben sie einige Vorteile: Sie sind einfach zu bedienen,  der User, der das Formular abschickt, sieht nicht die Adresse, an welche die Nachricht gesendet wird und man kann sie „relativ“ gut gegen Spammer schützen.

Was die Programmierung eines solchen Formulars angeht, geht das scheinbar schnell und problemlos. Ein paar Zeilen HTML, ein bisschen gescripte in PHP, und schon hat man ein funktionierendes Formular, über das der Seitenbesucher Kontakt aufnehmen kann. Gerade weil es scheinbar so leicht ist, ein Formular zu bauen, gibt es dazu im Internet Anleitungen und Tutorials wie Sand am Meer.

Genau hier aber fangen die Probleme schon an. Viele dieser Tutorials vernachlässigen, fast fahrlässig, die Frage, wie man ein Formular gegen Angreifer absichert. Gleich beim ersten Treffer einer Google Suche nach “php formular”  trifft man auf so ein Beispiel. In diesem Tutorial wird in drei Schritten beschrieben, wie ein Formular erstellt wird. Mit keinem Wort wird allerdings auf die Gefahren hingewiesen, die durch ein solches Formular für User und Seitenbetreiber auftreten können.

Zunächst vorab noch eine kleine Warnung:
Ich habe auf den ersten Seiten bei Google kein einziges Tutorial gefunden, das auf Sicherheitsaspekte eingeht. Wer also plant, mit Hilfe eines solchen Tutorials ein Formular zu erstellen, sollte sich zuerst überlegen wie er dieses absichern kann.

Ein kleiner Teil dieser Tutorials zeigt zwar noch wie man überprüft und ob alle Pflichteingaben getätigt wurden, geht aber ansonsten nicht auf weitere Gefahren, wie Mail-Header-Injektion, Cross-Site-Scripting, etc., ein. Solltet ihr ein gutes Tutorial kennen, bin ich gerne bereit, es hier zu posten.

Die im Folgenden angeführten Fehler sind nur ein Auszug aus einer Reihe von Fehlern, die gemacht werden können. Diese Aufstellung erhebt keinen Anspruch auf Vollständigkeit!

Keine Filterung der Daten

Die obersten Regeln in der Verarbeitung von Daten sind:

  1. „Traue niemandem“!
  2. „Traue niemandem“!
  3. „Überprüfe alles!“ (auch aus scheinbar vertrauenswürdigen Quellen)

Dementsprechend ist der größte anzunehmende Fehler,  Daten ungefiltert und ungeprüft weiter zu verarbeiten.

Wer diese Regeln beachtet,  hat schon ein großes Plus an Sicherheit bei der Verarbeitung von Formularen gewonnen. Die meisten unten aufgeführten Fehler treten durch Missachtung dieser Regeln auf.

Das „worst-case-Beispiel“

Der folgende Code demonstriert die Verarbeitung eines Formulars in PHP.

Bei diesem Beispiel handelt es sich um ein „worst-case-Beispiel“ und sollte auf keinen Fall für ein eigenes PHP-Formular verwendet werden!
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Unbenanntes Dokument</title>
</head>

<?php
if ($_REQUEST) {
	//mail verschicken
	$email = "";
	foreach ($_REQUEST as $feldname => $data) {
		$email .= "$feldname: $data \n";
	}

	mail("meineemail@meineseite.de", "neue Nachricht vom Kontaktformular", $email);

	//in die Datenbank eintragen
	$query = "INSERT INTO kontakt_anfragen SET ";
	foreach ($_POST as $feldname => $data) {
		$query .= $feldname . "=" . "'$data', ";
	}

	$query .= " ip = '".$_SERVER['REMOTE_ADDR']."'";
	$result = mysql_query ($query) or die (mysql_error());
}
?>

<body>
<form action="" method="post">
	<input type="text" name="name"  value="<?php echo $_REQUEST['name']; ?>"/><br />
   <input type="text" name="vorname"  value="<?php echo $_REQUEST['vorname']; ?>"/><br />
   <input type="text" name="telefonnummer"  value="<?php echo $_REQUEST['telefonnummer']; ?>"/><br />
   <textarea name="nachricht"><?php echo $_REQUEST['nachricht']; ?></textarea><br />
   <input type="submit" />
</form>
</body>
</html>

Code-Erklärung:
In diesem Beispiel werden alle im Array $_POST enthaltenen Einträge, die über das Formular übertragen worden sind, verarbeitet.

Fehler und Auswirkungen:
Hier wurden gleich mehrere Fehler gemacht, aus denen noch weitere Sicherheitslücken resultieren:

  • Der Inhalt der übertragenen Daten wird nicht überprüft.
  • Es wird nicht überprüft, ob noch weitere/zusätzliche Daten übertragen wurden.
  • Die Daten werden ungefiltert in die Datenbank geschrieben.
Mögliche Sicherheitslücken

Wenn die Daten nicht überprüft werden, kann  sich in den übertragenen Daten Schadcode befinden, der ungefiltert weiterverarbeitet wird.

Mail-Header-Injection

E-Mail Header. Aufzurufen bei Apple Mail: Darstellung>E-Mail>Alle Header

Eines der größten Risiken,  die Daten wie im obigen Beispiel zu verarbeiten, ist,  selbst ungewollt zum Spammer zu werden. Ein Angreifer kann mit Hilfe einer sogenannten  „Mail-Header-Injektion“ (ausführliche Analyse mit Beispiel) eine beliebige Anzahl weiterer E-Mail an unterschiedliche Adressen versenden.

Bei dieser Attacke wird die zeilenweise Verarbeitung des E-Mail Headers ausgenutzt. Jede versendete E-Mail besitzt einen Header-Bereich, wie z.B. auch eine HTML-Datei, in welchem unter anderem angegeben ist,  an welchen Server die E-Mail gesendet werden soll. Die Informationen im Header werden nicht direkt angezeigt und sind für den normalen User unsichtbar. Anschließend an den Header wird die eigentliche E-Mail angegeben.

Bei der Definition einer E-Mail handelt es sich im Prinzip nur um einen langen String (eine Zeichenkette). Dieser String kann mehrere Befehle zum Versenden unterschiedlicher E-Mails enthalten. Bei einem Angriff über eine “Mail-Header-Injection” schleust der Angreifer in den eigentlichen E-Mail-String, vereinfacht erklärt, zusätzliche E-Mails ein. Sollte dies einem Angreifer gelingen, wird von euerem Server, mit eurer IP, Spam an unterschiedliche Adressen versendet.

Weitere ungewollte Daten

HTML über das Developer-Tool des Safari-Browsers editieren ohne die ursprüngliche Datei verändern zu müssen

Eine weitere Sicherheitslücke ist die fehlende Überprüfung, ob noch weitere ungewollte Daten über das Formular übertragen worden sind. Es ist durch sehr einfache und weite verbreitete Mittel sehr einfach, zusätzliche Daten mit einzuschleusen.

Die verwendeten Werkzeuge,  solche Manipulationen zu bewerkstelligen,  sind eigentlich für die Entwicklung und Analyse von Websiten oder HTML-Code gedacht. In den meisten populären Browsern wie Safari, Chrome oder Opera sind diese schon vorinstalliert. Beim Browser Firefox können diese durch Plug-Ins wie „Firebug“ sehr schnell nachinstalliert werden. Diese Tools ermöglichen die Veränderung von HTML,  ohne auf die eigentliche Datei zugreifen zu müssen. Durch die Veränderung des HTMLs können so noch weitere Formular-Felder eingefügt werden, die noch weitere Daten an den Server übertragen können.

Je nach Weiterverarbeitung können damit zusätzliche (ungewollte) Informationen mit einer E-Mail übertragen oder in eine Datenbank,  bzw. in eine Datei auf dem Server,  geschrieben werden.

Die Daten ungefiltert anzeigen

In vielen Formularen werden sogenannte Pflichtfelder verwendet. Diese Felder müssen zwingend vom User ausgefüllt werden, um das Formular abzuschicken. Werden nicht alle Pflichtangaben vom User getätigt, wird er nach dem Absenden des Formulars wieder auf  die vorherige Eingabemaske umgeleitet, ohne dass eine E-Mail versendet wurde. Dabei werden die Daten, die der User anfangs eingegeben hat, weiterhin im Formular angezeigt, um ihm die Möglichkeit zur Korrektur und Vervollständigung zu geben.

Weitere ähnliche Sicherheitslücken können auch in folgenden Szenerien auftreten:

  • Suchanfragen
  • Bestellsysteme
  • Kommentar Funktionen eines Blogs
  • Forensysteme
  • Login-Scripte

In all diesen Szenerien werden vorherige Eingaben eines Formulars weiter verarbeitet und auf einer der folgenden Seiten als Text mit ausgeben. Dabei kann der Angreifer den User entweder dazu verleiten auf einen manipulierten Link zu klicken (z.B. bei einer Suchanfrage), oder schadhaften Code direkt in der Seite platzieren, wie es bei Foren oder Kommentaren der Fall sein können.

Bezogen auf unser Formular könnte die Programmierung so aussehen:

<input type =“text“ value=“<?php echo $feld;?>

Die Palette von möglichen Folgen reicht vom Ausspähen von Passwörtern bis zu Veränderungen an der eigentlichen Seite.

Weitere Informationen dazu: Cross-Site-Scripting (Englisch).

Ungefiltert in die Datenbank

Eine fast noch größere Gefahr bei der Verarbeitung eines Formulars ist, dass die Daten ungefiltert in die Datenbank geschrieben werden. Ohne eine Filterung kann es für den Angreifer möglich sein,  in die übertragenen Daten SQL-Befehle einzuschleusen, die ungewollte Aktionen in der Datenbank ausführen. Dadurch ist die gesamte Sicherheit der Web-Seite gefährdet. Mögliche Aktionen, die ausgeführt werden könnten, sind unter anderem die Daten auszulesen, diese zu manipulieren oder den gesamten Inhalt der Datenbank zu löschen.

Artikel im PHP Manual zu SQL-Injection.

Das Formular über „GET“ verarbeiten

Es gibt zwei Wege, Daten an einen Server zu übertragen. Jeder, der ein Formular erstellt muss im HTML-Tag <form> angeben, mit welcher Methode das Formular versendet werden soll. Die erste Methode ist, die Daten über „POST“ zu übertragen. Dabei werden die Daten „relativ“ unsichtbar an den Server übertragen.

Die andere Methode und wesentlich unsicherere  Art ist die „GET-Methode“. Dabei werden die Daten im Klartext lesbar über die URL übertragen (zu erkennen an den in der URL-Zeile des Browsers).

Zum einen besteht hier das Problem darin, dass im Klartext mitgelesen werden kann, welche Daten übertragen werden, zum anderen, dass ein User auf einen manipulierten Link stößt und so ungewollt Aktionen, wie z.B. das Löschen eines Artikels in seinem Blog, auslöst.

Mit JavaScript validieren

Mit zwei Klicks deaktiviert: JavaScript im Safari

Einige Formulare, die im Web zu finden sind – wie auch in meinem Kontaktformular – sind mit JavaScript-Funktionalität ausgestattet. Diese soll dem User vor dem Abschicken eines Formulars sagen, ob Eingaben fehlerhaft sind oder alle Pflichtfelder ausgefüllt wurden.

Wer sich jedoch  ausschließlich auf diese Validierung verlässt, könnte, aus Sicherheitsaspekten, auch ganz darauf verzichten.

JavaScript ist bei den meisten Browsern mit zwei Klicks deaktiviert, sodass die Validierung nicht mehr greift und alles ungefiltert übertragen und verarbeitet wird. Deshalb sollte eine zusätzliche Server-Seitige Validierung (z.B. mit PHP) eine Überprüfung und Filterung der Daten sicherstellen.

Fileupload ohne Überprüfung

Über Formulare lässt sich nicht nur Text übertragen! Es ist auch möglich, dem User die Möglichkeit zu geben, Files aller Art wie Bilder, PDF-Dateien oder Videos hochzuladen.

In diesem Fall geht die Gefahr direkt von den übertragenen Dateien aus, wenn es dem „bösen“ User möglich ist, ungefiltert ausführbare Dateien, wie PHP-Files, hoch zu laden.

Nachdem die Files hochgeladen wurden, muss der Angreifer „nur noch“ wissen, unter welchem Pfad die Dateien zu finden sind und hoffen, dass entsprechende Zugriffsberechtiungen auf dem (FTP-) Server gesetzt wurden um diese ausführen zu können.

Im schlimmsten Fall haben diese Files die Berechtigung, durch in den Files enthaltene Scripte, alle Daten auf dem Server zu löschen, oder diese zu verändern.

Daten aus einem Cookie laden

Unter Umständen kann es aus Gründen der Usability sinnvoll sein, die Eingabe von Daten auf mehrere Seiten aufzuteilen. Dies trifft insbesondere auf Bestellformulare in Online-Shops zu.

Während der Verarbeitung von solchen Formularen müssen die Daten vom ersten bis zum letzten Schritt transportiert werden, um am Ende die gesamte Bestellung abschicken zu können.

Bei vielen Formularen werden diese Daten oft in sogenannten Cookies gespeichert. Diese Cookies lassen sich jedoch auch von außen manipulieren, da die Daten lokal auf dem Rechner des Users gespeichert werden.

Deshalb gilt auch hier:

Selbst wenn die Daten ursprünglich validiert wurden, müssen sie, auch wenn sie wieder aus dem Cookie geholt werden, erneut validiert werden, da sie in der Zwischenzeit manipuliert werden konnten.

Desweiten sollten Login-Systeme,  die ebenfalls auf Cookies setzen, sich ebenfalls nicht zu sicher wähnen, wenn die einzige Barriere zu einem geschützten Bereich ein
logedIn = true ist, welches im Cookie steht.

Dies logedIn = true lässt sich ebenfalls nachträglich einfügen und ermöglicht es dem Angreifer, komfortabel und ohne Passwort in den Administrations-Bereich einzudringen zu können.

Nur die E-Mail Adresse validieren

In vielen Formularen besteht die einzige Validierung aus der Überprüfung E-Mail-Adresse. Hier wird mit einem vorher aus dem Internet gegoogelten „Regulären Ausdruck “ die E-Mail-Adresse auf ihre syntaktische Richtigkeit überprüft (ob sie einer, vom Regulären-Ausdruck definierten Schreibweise entspricht, z.B. name@domain.de).

Als wirklichen Schutz vor Angreifern kann man diese Validierung nicht sehen. Es hilft vielleicht dem User wenn er sich versehentlich vertippt hat, aber ein mehr an Sicherheit für sein Formular darf man sich davon nicht erwarten.

Eine E-Mail-Adresse kann „richtig“ aussehen, jedoch trotzdem ungültig sein. Wirklich absolute Sicherheit, ob es sich um eine gültige E-Mail-Adresse handelt, bekommt man erst, wenn man den User dazu zwingt, diese auch zu bestätigen (z.B. durch einen Link in einer E-Mail, welchen er anklicken muss, um diese zu bestätigen). Dies ist aber in den meisten Fällen eher unpraktisch.

Wer davon ausgeht, dass alle eingegebenen Daten korrekt und ohne Schadcode sind, weil eine gültige E-Mail-Adresse vorgegaukelt wird, muss schon sehr großes Vertrauen in seine User haben.

Captcha-Feld – aber sonst nicht validiert

Über den Sinn von Captcha-Feldern (Felder die überprüfen sollen, ob tatsächlich ein Mensch das Formular abschickt oder ob es sich um einen Bot handelt) kann man sich streiten. Ich persönlich bin der Meinung,  dass mit solchen Feldern zumindest ein gewisser Grundschutz aufgebaut werden kann.

Leider bieten Captcha-Felder nur einen minimalen Schutz, um sich vor Spam-Bots oder anderen Angriffen der Bots zu schützen, da auch diese immer mehr darauf konzipiert werden diese Felder zu knacken.

Ein weiterer Aspekt der von diesen Feldern nicht abgefangen werden kann, ist der Angriff auf das Formular von einem “echten” Menschen.

Wie auch bei den andern Fällen, gilt auch hier wieder: „Traue keinem und validiere alles und überprüfe nicht nur ob das Captcha richtig eingegeben wurde“.

Wer einmal überprüfen will, wie sicher “sein” Captcha-Feld ist, kann sich auf den Seiten Breaking a Visual CAPTCHA oder PWNtcha vergleichbare Images ansehen. Dort werden unterschiedliche Arten von Captcha-Images, mit  angegebener Fehler-Quote des Bilderkennungs-Algorthmus, vorgestellt.

Fazit

Durch die Beachtung einiger Grundregeln kann man die Sicherheit für sich und seine User deutlich erhöhen. Es gibt, wie bei allen Software-Lösungen, keinen 100%en  Schutz. Es passiert leider viel zu schnell, dass Sicherheitslücken entstehen, oft im Eifer des Gefechts und wenn etwas schnell fertig werden muss. Ich war auch schon in solchen Situationen. Hier muss jeder für sich selber entscheiden, wie er damit umgeht. Aus meiner Sicht ist es jedoch sinnvoller, bei sicherheitsrelevanten Funktionen einer Anwendung lieber etwas mehr Zeit zu investieren und vielleicht sogar noch einen Kollegen über die eigene Programmierung schauen zu lassen. Dann kann man mit ruhigem Gewissen die Arbeit an den Kunden weiter geben oder seine eigene Seite online stellen, ohne Angst haben zu müssen, dass irgendwann ein Angreifer die Seite umgestaltet oder die Seite nicht mehr erreichbar ist.

Es kann auch hilfreich sein, auf „Standard-Lösungen“ und Frameworks zurückzugreifen, selbst wenn hier immer das Argument der „weiten Verbreitung“ aufgeführt wird. Hinter solchen Projekten stehen jedoch im Normalfall viele Menschen, die auftretende Lücken schnell schließen und bei der Entwicklung an noch weitere Dinge denken können, als ein einzelner.