Immer wieder ist in den Nachrichten zu lesen, dass PHP unsicher sei. Das stimmt zwar, aber es stellt sich die Frage: Welche Sprache ist das nicht? Sicher bietet PHP einige Möglichkeiten, die in anderen Sprachen nicht möglich sind: so ist es z.B. per Default nicht möglich, in Java-Anwendungen eigenen Java-Code einzuschleußen. In PHP geht das von Haus aus. Aber auch in “sicheren” Sprachen können die Probleme entstehen.
Es gilt also der Grundsatz: Traue deinem Nutzer nicht!
Hält man sich strikt an diesen Grundsatz, kann eigentlich nichts schief gehen. Aber man muss sich eben daran halten.
Aus diesem Grund gehe ich heute mal genauer darauf ein, wie Upload-Daten von Usern geprüft werden können.
Die meisten Web-Anwendungen (u.a. auch Wordpress) ermöglichen das Upload von Benutzer-Dateien und beschränken diese Möglichkeit auf bestimmte Dateiendungen. Das halte ich für ein Sicherheitsrisiko! Die Endung einer Datei macht bekanntlich keinerlei Aussagen darüber, was für eine Datei wir wirklich haben. So ging erst vor ein paar Monaten eine Sicherheitslücke des Internet Explorers durch die Medien, weil dieser JavaScript innerhalb von GIF-Dateien ausführte. Es ist also in diesem Fall nicht das drin, was drauf steht.
Meiner Meinung nach muss man mit solchen Lücken des Benutzer-Systems immer rechnen. Es reicht nicht zu sagen: “Ist nicht mein Problem, der Fehler stammt vom IE.” Betroffene Nutzer werden sich genau daran erinnern, wo sie sich etwas eingefangen haben. Und das sollte man sich nicht leisten wollen: es dauert lange, bis man einen guten Ruf bekommt. Ein schlechter Ruf bekommt man dafür umso schneller.
Aber auch auf Servern existiert dieses Risiko. So wäre es denkbar, dass innerhalb einer JPEG-Datei PHP-Code enthalten ist. Ist der Server fehlerhaft eingestellt oder gelingt es einem Hacker, die .htaccess-Datei anzupassen, so wird jedes JPEG-Bild vor dem Ausliefern auf dem Server ausgeführt (inkl. PHP-Code). Auf diese Weise wäre es ein einfaches, Cookies des Benutzers auszulesen (z.B. Login-Daten), ohne dass es auch nur irgendjemand merkt (die Bild-Informationen könnte man ja entsprechend ausliefern). Solche Risiken sind sehr gefährlich: welcher Admin prüft schon regelmäßig, ob jemand an der Server-Einstellung gefummelt hat?
Eine weitere Angriffsmöglichkeit bestünde darin, dass bekannte Lücken von Programmen ausgenutzt werden (evtl. Bufferoverflow von Programmen). So ist evtl. das direkte Unterschieben präparierter Daten möglich.
Aus diesem Grund reicht es meiner Meinung nach nicht, Dateien lediglich auf Ihre Endung zu prüfen. Systeme wie Wordpress, in denen Nutzer Daten hochladen können, sind deshalb ein potentielles Risiko. Es ist also die Frage, wie kann ich sicherstellen, dass in den Dateien das drin ist, was drauf steht?
Für Bilder ist diese Möglichkeit sehr einfach: die Funktion getimagesize übernimmt die Prüfung der Bildformate GIF, JPEG, PNG und sogar des Flash-Formats SWF. Handelt es sich um gültige Dateien, werden Bildinformationen zurückgeliefert. Ansonsten erhält man als Rückgabewert “NULL”. Spätestens hier sollte man das hochgeladene Bild wieder Löschen, den Benutzer informieren und sicherheitshalber die Daten des Nutzers protokollieren, um ihn bei erneutem Versuch auszusperren.
Andere Formate sind schon komplizierter. Für viele Formate hilft aber die OpenSource-Bibliothek getID3, welche neben Audio, Video und Bildformaten auch gepackte Formate prüfen kann. Die Bibliothek kann natürlich noch weit mehr, aber sie prüft eben auch die Inhalte der Dateien.
include_once("getid3/getid3.php");
$file="test.mp3";
$tester = new getID3;
$filedata = $tester->analyze($file);
Nun sind in filedata alle Informationen enthalten, unter anderem das Audio-Format (unabhängig von der Endung) als auch Bitraten,…
Mit der Bibliothek können also schon einige Datei-Typen auf Inhalt geprüft werden. Für die Restlichen wird es schwieriger. Doch stellt PHP die Funktion mine-content-type zur Verfügung. Diese liefert zu einer Datei den angegebenen Mime-Type. Damit ist es möglich, den angegebenen Inhalt einer Datei unabhängig vom Dateinamen zu erhalten. Die Funktion stellt aber nicht sicher, dass es dann auch wirklich der korrekte Inhalt ist (der Mime-Type könnte ja gefälscht sein). Hier also aufpassen! Eine Möglichkeit, hier zu testen, besteht darin, den Dateiinhalt auf verdächtige Elemente zu durchsuchen. Das hängt jedoch vom Einsatzgebiet ab.