Fit4Php – Php Tutorial - Php für Einsteiger und Fortgeschrittene
Sicherheitsaspekte im Umgang mit Formularen und Variablen
Sicherheit von PHP-Skripts

Nachdem wir nun bei dem Thema angelangt sind, Daten über HTML-Formulare an PHP zu übergeben, müssen wir leider auch das Thema Sicherheit behandeln. Im Netz treiben sich unzählige Personen herum, welche teilweise auch automatische Skripts verwenden, welche Webseiten hacken wollen.

Warum? Nun, gehackte Webserver lassen sich wunderbar gebrauchen, um eigene Dateien auf den Webserver hochzuladen und diese dann über das Netz zu verbreiten. Auch sind Skripts immer wieder auf der Suche nach Möglichkeiten über gehackte Webserver Spam-Emailnachrichten zu versenden. Dies müssen sie tun, da normale Emailserver den Emailverkehr mittlerweile sehr stark überwachen, so dass es nicht zu Spam kommt. Emailserver, welche Spam verschicken, landen auch sehr schnell auf Blacklists. Somit müssen Spammer eine möglichst große Anzahl an verschiedenen Servern haben, von denen sie ab und zu Spam versenden. Emails dieser Server landen dann nicht direkt im Spam-Ordner, sondern werden ggf. im Posteingang noch angezeigt, wo der Spamversender sie gerne haben möchte. An eine solche große Servermenge kommt man nur heran, wenn man verschiedenste Server einfach hackt. Weiterhin wollen sicherlich Leute an die Benutzerdaten heran. Hier sind wieder die Spammer am Werk, welche gerne Emailadressen der Benutzer auslesen wollen, um sie zu bespammen. Auch wäre es denkbar, dass Leute unerlaubterweise Links auf der gehackten Seite plazieren, um an Besucher zu kommen…

Die Gründe für das Hacken sind vielfältig. Natürlich ist hacken illegal. Allerdings kommt man sehr schlecht an die entsprechenden Hacker heran, um sie zu bestrafen, da das Netz sehr offen ist und diese schnell untertauchen können. Somit hilft alles nichts. Wir müssen unsere Seiten sicher machen, damit kein Angriff von außen geschieht.

Formulare und übergebene Variablen: Angriffspunkt für Hacker

Die Formulare sind der größte Angriffspunkt für Hacker. Genauer gesagt, die Felder, welche über die Formulare an PHP übergeben und ausgewertet werden. Deshalb ist es nötig die herankommenden Daten zu überprüfen. PHP-Skripte sollten niemals den Variablen direkt vertrauen und diese in ihre Programme einfach einbauen. Dies ist ein großes Prinzip, welches unbedingt zu befolgen ist. Leider ist es dadurch nötig, komplizierte Überprüfungen der Eingabe zu machen, welche leider unseren Code etwas unübersichtlich machen werden.

register_globals = off

In früheren Zeiten von PHP wurden Variablen, die über GET oder POST geschickt wurden, direkt als Variablen im PHP-Skript veröffentlicht. Dies sollte dem Benutzer ermöglichen, sehr einfach auf diese zuzugreifen. Mittlerweile ist die Funktion register_globals aber standardmäßig auf off gesetzt. Sie sollte keinesfalls auf on gesetzt werden, um die Einfachheit des Variablenzugriffes zu gewährleisten. Welches Sicherheitsloch dabei entsteht, wird durch folgenden PHP-Code demonstriert:

<?php
if ((strcmp(username,‘benutzer’)==0) && (strcmp(passwort,‘geheim’)==0))
     login_successfull = 1;
if (login_successfull == 1)
{
   // Hier Anweisungen ausführen, die nur für den eingeloggten Benutzer möglich sind.
}
?>

Das Skript sollte normalerweise wie folgt ablaufen: Es wird eine Variable ‘benutzer’ und eine Variable ‘passwort’ über ein Formular eingegeben. Nun wird der eingegebene Benutzername und das eingegebene Benutzerpaßwort mit den Daten im Skript mit der Funktion strcmp verglichen. Hier könnte selbstverständlich auch ein komplizierterer Datenbankvergleich stattfinden. Ich habe den Code jedoch bewußt einfach gehalten. Dann wird die Variable login_successfull auf 1 gesetzt, um in der nachfolgenden If-Abfrage ein postives Ergebniss zu erzeugen.

Nun kommt der Angreifer. Er kann auch über die Browserzeile die Variable login_successfull auf 1 setzen. Die Variable login_successfull ist somit im gesamten Skript immer 1. Somit brauch die erste If-Abfrage gar kein postives Ergebnis liefern. Der Benutzer ist immer eingeloggt und somit die Webseite gehackt.

Das Loch, welches exisitert, ist, dass die Variable login_successfull nicht in der ersten Zeile des Skriptes sofort mit ‘0′ vorbelegt wird oder eben halt, dass register_globals auf ‘on’ steht.

Include-Attacke

Manchesmal verwendet man eine Art Verteiler-PHP-Skript, um weitere Skripte aufzurufen. Die URL des Aufrufes kann dann z.B. wie folgt aussehen: http://testserver/index.php?aktion=datensatz_bearbeiten

Dies ist ein sehr gutes Vorgehen, will man z.B. vor dem gesamten dahinterstehenden Web ein Einloggen des Benutzers erzwingen. Das Einloggen wird mit Hilfe des Verteiler-PHP-Skriptes erzwungen, während die eigentlichen Aktionen in weiteren PHP-Skripts stattfinden. So könnte die PHP-Datei index.php aus der obigen URL beispielsweise wie folgt aussehen:

<?php
// Code, der überprüft, ob richtig eingeloggt ist
// …
// …
 
include ($_GET["aktion"]..php’);
 
aktionsaufruf ();
 
?>

Die Möglichkeit der Attacke springt nicht sofort ins Auge. Allerdings ist es hier möglich, die Aktions-Variable, welche von der URL kommt, zu verändern. Das wäre noch nicht so schlimm, da die Aktionen ja entsprechend vorhanden sind und der Benutzer dann nur Aktionen ausführt, die er auch ausführen darf. Allerdings akzeptiert die Variable include auch URLs. D.h. mit Hilfe des include-Statements wird auf eine externe Seite zugegriffen, dort ein PHP-Skript heruntergeladen und dieses im lokalen Kontext ausgeführt. Somit kann der Hacker alle möglichen Anweisungen auf dem eigenen Webserver ausführen. Ein offenes Scheunentor.

Wie kann man dies verhindern? Nun, wir benötigen eine Liste von erlaubten Aktionen in dem Verteiler-PHP-Skript. Nur erlaubte Aktionen werden mit include eingebunden und abgearbeitet. Sicher bedeutet dies einiges an Aufwand zu programmieren. Jedoch sollte man diesen nicht scheuen, will man nicht auf die Sicherheit seiner Webseite verzichten.

Eine andere Möglichkeit wäre, die Variable ‘aktion’ sehr strikt zu kontrollieren und z.B. nur kleine Buchstaben in dieser zuzulassen und nichts weiter. Somit kann der Hacker keine URL in der Variablen mit einschmuggeln.

SQL-Injection Attacke

Sicherlich ist es erwünscht, Variablen aus dem Netz in ein SQL-Kommando zu übernehmen. Beispielsweise muss, wenn ein Benutzer sich einloggt und die Benutzerdaten in der SQL-Datenbank liegen, eine SQL-Abfrage nach dem Passwort gestartet werden:

<?php
“SELECT passwort FROM benutzertabelle WHERE benutzer=$_GET['benutzer']‘”
?>

Dies sieht zunächst einmal nicht schlimm aus. Allerdings wenn wir daran denken, dass für die Variable ‘benutzer’ aus dem Netz beliebiges kommen kann, könnte ein Hacker folgendes für diese Variable vorgeben:

benutzer = ‘; DROP DATABASE `benutzerdatenbank`;

Was passiert? Nun die komplette SQL-Abfrage wird nach Einfügen der sehr merkwürdig aussehenden Variablebelegung wie folgt aussehen:

<?php
“SELECT passwort FROM benutzertabelle WHERE benutzer=;DROP DATABASE `benutzerdatenbank`;’”
?>

Es ist ein SQL-Kommando so dazwischengeschoben worden. Auch Anführungszeichen vor und hinter der Variable haben nichts genutzt. Die dazwischengeschobene Variable schließt das Kommando einfach wieder. Danach infiltiert sie ein tödliches SQL-Kommando, dass die ganze Datenbank gelöscht wird.

Wie kann man solchen Attacken entgegenwirken? Nun wiederrum hilft nur eine restriktive Überprüfung der Strings. Alternativ lassen sich auch mit der Methode mysql_real_escape_string bösartige Strings mit Anführungszeichen verändern, so dass alle Anführungszeichen escaped sind und damit nicht auf Kommandoebene, sondern auf Variableebene betrachtet werden.

Mail-Attacke

Kommen wir zu der letzten in meinen Augen sehr wichtigen und gefährlichen Attacke. Sie zerstört nicht die Datenbank oder späht Daten aus, sondern wird dafür benutzt, Spam zu verschicken. Dreh und Angelpunkt ist die Funktion mail von PHP.

Diese wird wie folgt aufgerufen:

<?php
mail($to, $betreff, $nachricht);
?>

Angenommen, wir sind vorsichtig und die Variable $to ist fest gesetzt. Wir wollen nur Emails an unsere eigene Adresse zustellen, um z.B. die Eingaben in einem Webformular an unsere Emailadresse zu senden. Allerdings soll der Betreff frei wählbar bleiben und wird aus dem Netz geholt.

Das Emailprotokoll sagt, dass eine Email aus verschiedenen Header-Zeilen besteht. Eine davon ist die Betreffzeile. Jede neue Zeile beginnt mit einem Zeilenvorschub. Dann kommt ein Mail-Kommando und dann der entsprechende String des Kommandos.

Nun kann der Angreifer hingehen und den $betreff hinterlistig ändern, z.B. in “Betreff
bcc:opfer@somewhere.com”.

PHP wird eine neue Zeile einfügen und darin einfügen, dass die Email nicht nur an uns selbst sondern auch an die Emailadresse opfer@somewhere.com per BCC gesendet wird. Somit kann man in vielen Formularen das Betrefffeld hacken, um diese Formulare dazu zu mißbrauchen Spam vom fremden Server zu senden. Hier ist also wirklich Vorsicht geboten.

Lösen kann man das Problem wiederrum, indem man entsprechend auf Zeilenvorschübe filtert. Werden keine Zeilenvorschübe zugelassen, so läuft die Attacke ins Leere.

Cross-Site Skripting

Diese Attacke bezieht sich mehr auf die Client-Seite bei der Benutzung der Webseite. Cross-Site Skripting kann dann durchgeführt werden, wenn es dem Benutzer der Webseite möglich ist, HTML-Code in die Webseite einzubauen, welcher dann später anderen Benutzern auf der Webseite angezeigt wird. Auch Javascript-Code ist gefährlich. Im HTML-Code beschreibt der Angreifer dann beispielsweise ein Login-Formular für die Webseite. Als Formularadresse gibt er dann aber nicht den Orignialserver an, sondern er sendet die Formulareingaben an seinen eigenen Server. Schwups ist es passiert und der Angreifer kann alle Benutzerdaten auslesen, die auf der Webseite in seinem gefälschten Formular eingegeben werden. Die Opfer merken davon nicht viel. Sie vertrauen auf die Webseite, dass Login-Formulare auf der Webseite sie auch wirklich einloggen (dazu sind sie ja da).

Weitere Attacken

Es sind noch eine große Menge weiterer Attacken denkbar. Das Prinzip sollte hier klar geworden sein: Niemals den Angaben, die aus dem Web heraus kommen, trauen. Immer die Variablen entsprechend einschränken, überprüfen und merkwürdige nicht erlaubte Variablen zurückweisen. Dies setzt leider etwas Programmieraufwand voraus. Leider ist es auch in der Vergangenheit immer wieder dazu gekommen, dass professionelle Skripts korrumpierbar waren und geflickt werden mussten. Leider greifen hier bei PHP und auch bei anderen Skriptsprachen keine guten Sicherheitskonzepte, so dass die Sicherheit dem jeweiligen Programmierer überlassen bleibt.

Beispiel für das Filtern von HTTP-Eingaben

Was muss ich nun tun, um meinen Server nun sicher zu machen? Oben ist eine Anzahl von Einfallstoren gelistet, welche geschlossen werden müssen. Man sollte register-globals auf jeden Fall auf off schalten (was die Standardeinstellung ist). Weiterhin sollte man keine Includes mit Variablen machen, die über die HTTP-Eingabe kommen, sondern immer Includes statisch machen und nur Dateien die auf dem gleichen Server liegen, inkludieren. Alles andere ist zu gefährlich. Bei Emailversand sollte man die eingegebenen Emailadresse und Variablen überprüfen, ob sie keine Leerzeichen oder Steuerzeichen beinhalten. SQL-Injektion-Attacken kann man abblocken, indem man alle Variablen zu Beginn einfach filtert. Eine wirkungsvolle Methode, um eine Vielzahl von Attacken abzuwehren, ist es, nur bestimmte Zeichen in der Variable zuzulassen. Folgende kleine Funktion erlaubt es, nur kleine Buchstaben in den Variablen zu übergeben. Es kann einfach angepaßt werden, wenn weitere Zeichen zugelassen werden sollen:

<?php
function onlyAllowSaveCharacters ($input)
{
 $erlaubteZeichen = explode(:,
            “a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z”);
 $index = 0;
 $output =;
 
 while (in_array($input[$index],$erlaubteZeichen)==true)
 {
   $output .= $input[$index]; 
   $index++;
   if ($index>strlen($input))
   break;
 }
 return $output;
}
?>

Wenn man mit diesen Einschränkungen nicht leben kann und beispielsweise auch Sonderzeichen in die SQL-Abfrage übernehmen möchte, muss man entsprechende Zeichen casten, damit sie richtig übernommen werden. PHP stellt einige Funktionen dazu zur Verfügung, die einen unsicheren String in einen sicheren String umformen. Leider muss dieser sichere String bei der Ausgabe auch wieder in einen unsicheren zurück verwandelt werden. Die nötigen Funktionen in PHP heißen hier addslashes() und stripslashes().

Cross-Site Skripting kann man unterbinden, indem man generell HTML- und Javascript-Eingaben herausfiltert bzw. die entsprechenden Strings so castet, dass der Benutzer hinterher nicht einen interpretierten Code im Browser sieht (also das was mit dem HTML-Code beschrieben wird), sondern den Quelltext des Codes sieht. Am Besten man schließt HTML-Tags ganz aus. Dies kann man z.B. tun, indem man die Größer und Kleinerzeichen des HTMLs nicht erlaubt.

Zum Inhaltsverzeichnis