Sichere PHP-Skripts mit Hardened-PHP
Schotten dicht!
Ungewollte Schlupflöcher
Sichere PHP-Skripts mit Hardened-PHP
Mittlerweile ist PHP als Programmier- und Skript-Sprache fest etabliert. Sie ermöglicht einen leichten Einstieg für Anfänger und bietet gleichzeitig auch eine hohe Flexibilität für erfahrene Entwickler. Hinzu kommt, dass PHP mittlerweile auf quasi jedem Webserver zur Verfügung steht.
Insbesondere Skripts von unerfahrenen Programmierern führen jedoch auf Grund mangelnder Vorsicht oft dazu, dass Angreifer durch spezielle Skriptaufrufe ungewollte Aktionen auf dem Server ausführen können. Diese Gefahr lauert potenziell auch bei der Installation von fremden Skripts, zum Beispiel einem Gästebuch, einem Redaktionssystem oder einer Bildergalerie. Webhoster und Serverbetreiber müssen daher Maßnahmen ergreifen, um derartige Angriffe möglichst effektiv zu verhindern.
Bordmittel von PHP
Sichere PHP-Skripts mit Hardened-PHP
PHP selbst bietet Bordmittel, um die Funktionalität von PHP in gewissen Grenzen einzuschränken und somit zum Beispiel per safe_mode einzelne Einfallsmöglichkeiten zu unterbinden. Aber für einen umfangreichen Schutz auch gegen unbekannte Angriffe gilt es die Sicherheit von PHP durch zusätzliche Checks und Filter zu erhöhen. Eine solche Härtung für sowohl PHP 4 als auch PHP 5 bietet das Projekt Hardened-PHP von Stefan Esser (www.hardened-php.org). Es handelt sich hierbei um ein Patch-Paket für den Original-Sourcecode von PHP. Unterstützt werden derzeit in der Regel die letzten beiden stabilen Versionen von PHP 4.x sowie die aktuelle PHP 5.x-Version. Die Installation ist relativ einfach.
Je nach verwendeter PHP-Version bietet Hardened-PHP Patches für spezielle Sicherheitslücken. Wird eine potenziellen Sicherheitslücke bekannt, so kann sie auf diesem Weg auch vor Erscheinen einer neuen, offiziellen PHP-Version behoben werden. Des Weiteren enthält Hardened-PHP Backports von Fehlerkorrekturen aus einer späteren PHP-Version. So enthielt zum Beispiel die Hardened-PHP-Version für PHP 4.3.9 Korrekturen, die erst später in Version 4.3.10 veröffentlich wurden.
Grundschutz für die Zend-Engine
Sichere PHP-Skripts mit Hardened-PHP
Begriffe wie Bereichsüberschreibungen beziehungsweise Pufferüberlauf fallen regelmäßig in Zusammenhang mit Sicherheitslücken in Software. Daher wurden in Hardened-PHP Schutzmaßnahmen für den Kern von PHP, die Zend-Engine, implementiert. Der Zend-Speichermanager, die Behandlung von verketteten Listen und auch die Behandlung von Hash-Tabellen wurden über so genannte Canaries abgesichert. Weiterhin wurde zur Vermeidung so genannter Format-String-Angriffe ein Ersatz für die printf-Funktion der libc geschaffen, über den es möglich ist, beispielweise Extensions, die gegen Hardened-PHP kompiliert sind, zentral vor gewissen Angriffen zu schützen. Hierdurch wurde die Bedeutung des Format-Strings %n entfernt, der in der Regel nicht benötigt wird.
Die realpath-Funktion unter Linux/glibc ermöglicht es, zu einem Dateinamen wie /etc/hosts/../passwd den komplett aufgelösten Pfad zu ermitteln, im Beispiel /etc/passwd. glibc prüft an dieser Stelle allerdings nicht, ob der durch .. entfernte Teil des Pfadnamens überhaupt ein Verzeichnis ist. So könnte man beispielsweise über nachfolgenden PHP-Code beabsichtigen, den Namen einer Datei nach einem festen Schema zusammenzusetzen und deren Inhalt anzuzeigen:
echo file_get_contents("/abc/artikel_$nr.txt");
?>
Ist in diesem Fall aber $nr unglücklich gewählt (zum Beispiel 15.txt/../../def), könnte über den resultierenden Pfad /abc/artikel_15.txt/../../def.txt eine Datei namens def.txt aus dem Root-Verzeichnis gelesen werden. Hardened-PHP würde an dieser Stelle bemerken, dass /abc/artikel_15.txt kein gültiges Verzeichnis, sondern lediglich eine Datei ist, und somit den Zugriff unterbinden. Anmerkung: Auf Systemen ohne glibc-realpath-Funktionalität wurde das realpath-Verhalten von PHP bis Version 4.3.9 auf gleiche Weise emuliert.
Außerdem weist Hardened-PHP Include-Dateinamen zurück, die Ascii.NUL-Zeichen enthalten. Diese dienen bei C meist als Endmarkierung für Zeichenketten. In URLs könnten sie beispielsweise durch urlencoding eingeschleust werden.
Auch werden überlange Include-Dateinamen gar nicht akzeptiert. Vor PHP 4.3.10 hat PHP selbst im safe_mode nur die ersten 4095 Zeichen eines Dateinamens zur Überprüfung verwendet. In diesem Fall wäre es möglich, den Namen der Datei, welche eigentlich geöffnet werden soll, so zu ergänzen, dass safe_mode den Zugriff akzeptiert und ungeachtet einen Dateinamen außerhalb der Verzeichnisbeschränkung liefert.
Schutz vor böswilligen Includes
Sichere PHP-Skripts mit Hardened-PHP
Ist es möglich, den Namen von Include-Dateien im Skript-Aufruf zu beeinflussen, so kann dies ebenfalls einen möglichen Angriffspunkt darstellen. Dank der fopen-Wrapper in PHP ist es möglich, Dateien über einen URL auch von einem entfernten Server zu öffnen. Dass es gleichermaßen auch möglich ist, Include-Dateien von einem entfernten Server zu nutzen, ist zwar konsequent, kann in der Praxis jedoch erhebliche Sicherheitsprobleme mit sich bringen. Daher sind bei Hardened-PHP so genannte remote includes verboten. Ein GET-Request würde entsprechend im Webserver-Access-Log protokolliert. Aber ein POST-Angriffsversuch bleibt in der Regel unentdeckt. Außerdem ist es nicht erlaubt, eine per POST-Request auf den Server übertragene Datei per include zu nutzen.
Heuristik für Shell-Kommandos
Sichere PHP-Skripts mit Hardened-PHP
Bei Shell-Aufrufen ist die Art der Weitergabe von Skript-Parametern an externe Programme sehr wichtig. Werden die Werte hierbei vorab nicht entsprechend bearbeitet ? zum Beispiel mittels escapeshellargs() ?, so ist es möglich, über Shell-Sonderzeichen wie Semikolon oder Pipe weitere Kommandos auszuführen. Die Heuristik von Hardened PHP sucht daher bei Shell-Aufrufen nach Bestandteilen, welche mit gewisser Wahrscheinlichkeit aus GET-/POST-Variablen stammen und auf unsichere Weise in Shell-Aufrufen verwendet werden.
Da dies aufwendig und nicht hundertprozentig sicher möglich ist, wird diese Funktion derzeit nur zum Logging verwendet, um nicht versehentlich Kommandos zu blocken. Anderenfalls könnte die Funktion von einem Angreifer sogar eventuell selbst für einen Angriff genutzt werden, um gezielt einzelne Kommandos an ihrer Ausführung zu hindern.
In einigen Skripts werden fälschlicherweise Aufrufe wie extract($_GET); verwendet, um im Fall von deaktiviertem register_globals dessen Funktion zu emulieren. Auch existiert zu diesem Zweck in PHP die Funktion import_request_variables(). Auf diesem Wege wäre es dann aber auch möglich, superglobale Variablen wie $_SERVER[?DOCUMENT_ROOT?] zu überschreiben. Hardened-PHP schützt an dieser Stelle vor der Überschreibung der Superglobals.
Einschränkung für Funktionen
Sichere PHP-Skripts mit Hardened-PHP
Über die Angabe disabled_functions in der php.ini kann die Ausführung einzelner PHP-Funktionen verhindert werden. Problematisch ist dies jedoch insbesondere beim Betrieb von PHP als Modul. Hierbei ist es nämlich nicht möglich, über separate php.ini-Dateien Funktionen für einen bestimmten Virtual Host zu deaktivieren, sie auf einem anderen hingegen zu erlauben. Hardened-PHP bietet hierfür die Möglichkeit klar definierter White- und Blacklists.
Auch ist es notwendig, die aus XSL-Dateien möglichen Funktionsaufrufe einzuschränken. Stammen die Dateien aus nicht vertrauenswürdiger Quelle, wäre es möglich, hierüber beliebige PHP-Funktionen auszuführen. Ähnliches gilt für Funktionsaufrufe in eval() beziehungsweise preg_replace(). Daher wurden in Hardened-PHP auch für jene Szenarien jeweils separate White- und Blacklists implementiert, konfigurierbar über eine INI-Datei. Außerdem stellt Hardened-PHP in den Skripts eine sandbox()-Funktion bereit, die es dem Skript-Programmierer erlaubt, für einzelne Code-Blöcke gezielt Rechte für Funktionsaufrufe zu definieren.
In PHP 5.x wurden Input-Filter-Hooks eingeführt. Diese können bei Beginn eines Skripts genutzt werden, um eintreffende Variablenwerte zu überprüfen und gegebenenfalls zu modifizieren. Diese Funktionalität wird von Hardened-PHP zusätzlich auch unter PHP 4.x bereitgestellt. Über diese Hooks unterstützt es die Varfilter-Extension von Hardened-PHP, flexibel Variablenbegrenzungen für Anzahl, Namen, Array-Tiefe, Inhaltslänge oder Inhalt zu definieren.
Außerdem erweitert Hardened-PHP den PHP-Core um File-Upload-Hooks. Darüber ist es möglich, verschiedene Überprüfungen vor, während und nach der Übertragung einer Datei an PHP durchzuführen. Vor einer Auswertung könnte eine Datei bereits abhängig von Dateiname und Formular-Zielvariable überprüft werden. Während der Verarbeitung eines POST-Requests könnte pro Block eine Überprüfung der Dateigröße oder des Dateiinhalt durchgeführt werden. Nach einem verarbeiteten Datei-Upload wäre es denkbar, die Datei nochmals abschließend zu prüfen. Die Funktionalität dieser Hooks ist für die eigentlichen PHP-Skripts transparent und erlaubt die Manipulation von Datei-Uploads, bereits bevor ein Skript über den Upload informiert wird.
Fazit
Sichere PHP-Skripts mit Hardened-PHP
Selbstverständlich ist es nicht möglich, eine PHP-Installation lediglich durch Hardened-PHP komplett abzusichern. Aber die aktuelle Version enthält viele Möglichkeiten, sich vor einigen Angriffsarten gezielt zu schützen. Hierbei steht jeweils auch der Schutz vor bisher unbekannten Angriffen klar im Vordergrund. Zusätzlich sollte man für Absicherung des Servers sorgen. Im Falle von Shared Webhosting gehört hier auch das Abgrenzen der Skripts einzelner Kunden per User-Switching dazu. Auch sollte man beim Einsatz fremder Skripts die Code-Qualität beurteilen und auf aktuelle Sicherheitswarnungen und Patches in den etablierten Sicherheits-Mailing-Listen und -Foren achten.