IT Sicherheit

IT Sicherheit für PHP 7 Webseiten erhöhen

Lesezeit ca. 10 Min.

Im zweiten Teil der Artikelserie über IT Sicherheit beschreibe ich, wie man die IT Sicherheit für PHP 7 Webseiten erhöhen kann.

Ich habe mich mit diesem Artikel ein wenig schwer getan. Zum einen weil ich sehr viel Material zu möglichen Angriffsflächen in PHP gefunden habe und lange überlegt habe, was ich davon in diesem Artikel verwenden (alles wäre nicht möglich gewesen, weil es den Rahmen eines Blog Artikels gesprengt hätte) und wie ich die Informationen präsentieren soll. Ich habe mich entschieden, die einzelnen Angriffsmöglichkeiten darzustellen und zu jeder Art eine Beschreibung der Sicherheitslücke, die Möglichkeiten des Schutzes dagegen und ein wenig Beispielcode aufzuführen. Am Ende des Artikels führe ich noch einige Links zu weiterführender Literatur auf.

Informationsgewinnung

Wie bereits im letzten Artikel IT Sicherheit beim Apache Webserver angedeutet, ist es auch für die Absicherung von PHP Anwendungen grundsätzlich hilfreich, dem Angreifer möglichst wenig Informationen über die verwendete Entwicklungsumgebung zu geben. Dies ist natürlich schwierig, wenn man direkt Skripte mit der Endung .php aufruft. Besser ist es, den Einstieg in die Webseite mit dem Apache Modul mod_rewrite auf ein einziges Skript (i.d.R. index.php) zu routen. Damit verschleiert man die verwendete Skriptsprache für die Besucher der Webseite.

Der Seitenaufruf würde dann so aussehen:


http://www.meine-domain.de/

und würde auf “http://www.meine-domain.de/index.php” umgeleitet werden.

Die erste Maßnahme, um die PHP Version zu verbergen, ist die Option expose_php. Setzt man diese in der php.ini auf Off, so werden keine Informationen über die verwendete PHP Version angezeigt.


expose_php = Off

Security through obscurity oder Security by obscurity (deutsch „Sicherheit durch Obskurität“, auch „Sicherheit durch Unklarheit“) ist ein Prinzip in der Computer- und Netzwerksicherheit. Es versucht, die Sicherheit eines Systems oder eines Verfahrens zu gewährleisten, indem seine Funktionsweise geheim gehalten wird.

Fehlererzeugung

Ein gerne verwendeter Trick, um auf den Einsatz von PHP zu prüfen, ist das Provozieren von Fehlermeldungen. Deswegen sollten in einer Produktivumgebung unbedingt die folgenden Optionen in der php.ini ausgeschaltet werden:


display_errors = Off
display_startup_errors = Off
error_reporting = 0
html_errors = Off

Da der Entwickler aber auch in der produktiven Umgebung auftretende Fehlermeldungen noch sehen will, sollte das ErrorLog in eine Datei auf dem Webserver geschrieben werden. Hierzu gibt es auch zwei Optionen in der php.ini, die gesetzt werden müssen:


log_errors = On
error_log = "logs/error.log"

Cross-Site Scripting (XSS)

Cross-Site Scripting ist eine der am häufigsten auftretenden Attacken auf Webseiten. Dabei wird – vereinfacht ausgedrückt – Skript-Code (meistens Javascript, aber auch jede andere in einem Browser ausführbare Skriptsprache) in die Webseite eingefügt und zur Ausführung gebracht. Die üblichen Sicherheitsbeschränkungen des Document Object Model (DOM) können umgangen werden, da dieser Code im Kontext der ihn anzeigenden Seite ausgeführt wird.

Da XSS vordergründig keine direkte Gefahr für den Webserver darstellt, wird die Bekämpfung von Cross-Site Scripting von vielen Entwicklern sträflich vernachlässigt. XSS kann zum Diebstahl von Session-Cookies, Login-Daten oder zur Installation von Software auf dem Rechner des Clients genutzt werden.

Beispielsweise könnte ein Webformular in einem Blog, mit dem Besucher ihre Kommentare hinterlassen können und aus ästhetischen Gründen HTML-Tags erlaubt, für XSS Attacken verwendet werden. Ein Angreifer könnte jeden Besucher auf seine eigene Seite umleiten. Hierzu wäre nur der folgende Code erforderlich, der in die Kommentarzeile eingegeben werden müsste:



Klassische Angriffspunkte für XSS sind:
– Suchformulare
– Login-Formulare
– Foren
– Blogs
– Online-Shops
– u.a.

Geeignete Maßnahmen gegen XSS durch PHP besteht im Filtern der Eingabedaten, welche über die URL oder einen POST Request kommen. Der erste Schritt wäre die Verwendung der PHP-Funktion strip_tags(). Damit werden erst einmal alle HTML-, sogar alle SGML-Tags herausgefiltert.
Ferner könnte man mit der PHP-Funktion htmlentities() noch vorhandene Sonderzeichen wie einzelne Klammern <>, Anführungszeichen, etc. entweder ganz entfernen oder in ihre HTML-Entitäten umwandeln.

Etwas aufwendiger wird die Sache, wenn man dem Benutzer die Eingabe von HTML-Tags gestatten möchte. Hierzu kann im einfachsten Fall eine Tag-Whitelist erstellt werden und diese als Option an die PHP-Funktion strip_tags() übergeben werden.


$clean_html = strip_tags($html, '

');

Für komplexere Szenarien kämen spezielle Tools, wie z.B. der HTML Purifier zum Einsatz.

Cross-Site Request Forgeries (CSRF)

CSRF ist im Grunde genommen genau das Gegenteil von XSS: während XSS eine Webseite dazu nutzt, Code im Browser des Benutzers auszuführen, werden bei CSRF die im Browser eines Nutzers gespeicherten Informationen (z.B. sein Session-Cookie) missbraucht, um auf einer Webseite in dessen Namen Aktionen auszuführen. So kann z.B. der Angreifer sich mit den Anmeldedaten des Benutzers in einen Account einloggen und dort alles tun, wofür der Benutzer die Berechtigung hat.

Die beste Abwehrmaßnahme gegen CSRF besteht darin, für jede Transaktion der Webapplikation eine gemeinsame geheime Information zwischen Server und Browser auszutauschen. Hierzu gibt es folgende Möglichkeiten:

Synchronizer Token Pattern (STP)

Bei STP wird ein sogenanntes Page-Token in einem Hidden-Field eines Formulars auf der Webseite verwendet. Dieses Token kann eine beliebige Zeichenkette oder Zahl sein.



Cookie

Das CSRF-Token kann auch in einem Cookie gespeichert werden. Dieses wird im HTTP-Header deklariert.


Set-Cookie: Csrf-token=asCsE%sk$12paoE939koi!703; expires=Sat, 9-Nov-2017 12:45:27 GMT; Max-Age=31449600; Path=/
HTTP-Header

Ein CSRF-Token kann auch über den HTTP-Header übermittelt werden. Hierzu wird der Header x-Csrf-Token verwendet.

SQL Injection

SQL-Injection ist eine der gefährlichsten Angriffsarten auf Webserver und Webanwendungen. Hierbei macht sich der Angreifer zu nutze, dass Daten über ein Eingabefeld im Formular nicht hinreichend validiert wird.

Anwendungsparameter werden häufig über die URL per GET Request an die Anwendung übertragen. In diesem Fall ist es zwingend erforderlich, die so übertragenen Daten genau zu überprüfen, bevor sie weiterverarbeitet werden. Hierzu gibt es die Möglichkeit, Filter einzusetzen, welche schon im Vorfeld bestimmte ungewollte Eingaben entfernen. Ferner können Validatoren verwendet werden, welche ebenfalls die Eingabedaten nach diversen Kriterien überprüfen, damit die Daten den Business Regeln entsprechen.

Zunächst ein Beispiel, bei dem eine SQL Injection ohne weiteres möglich wäre:


$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
// jetzt die Query ausführen

Es spielt im übrigen keine Rolle, ob so ein Formular über die GET oder POST Methode übertragen wird. In beiden Fällen lassen sich die Eingabeparameter manipulieren.
Würde nun die Variable $username z.B. mit dem Inhalt “Peter; SHOW TABLES;” übergeben, so erhielte der Angreifer eine Auflistung sämtlicher Tabellen in der Datenbank. Und mit weiteren solchen angehängten SQL-Befehlen könnte er die Datenbank angreifen (sofern der Datenbank-User die nötigen Berechtigungen hätte).

Nun das gleiche Beispiel mit einer Validierung des Eingabeparameters:


$username = $_GET['username'];
$user = strstr($username, ';', true);

$sql = "SELECT * FROM user WHERE user = '$user'";
// jetzt die Query ausführen

Durch den dritten Parameter, der auf TRUE gesetzt ist, in der PHP-Funktion strstr() wird von dem String $username nur der Teil vor dem dem Suchstring “;” zurückgegeben. Alles, was danach im Ausgangsstring steht, wird abgeschnitten und damit auch der Schadcode für das SQL-Statement.

Parametermanipulation

Ich werde nur ein Beispiel für einen Angriff durch die Manipulation eines per URL übergebenen Parameter zeigen.


include ($_GET['page']);

Durch Anhängen einer beliebigen Datei, z.B. eine Systemdatei, an den URL-Parameter page kann diese Datei ausgelesen werden, wenn der Webserver die entsprechenden Rechte dazu hat.


http://www.meine-domain.de/index.php?page=/etc/passwd

In diesem Beispiel könnten alle Passwörter auf einem Apache Webserver ausgelesen werden.

Zum Schutz vor einem solchen Hack sollte die Konfigurationsoption open_basedir gesetzt werden. Dadurch können nur Dateien unterhalb des angegebenen Verzeichnisses gelesen werden. Aber Vorsicht: auch in diesem Verzeichnis können sich Dateien mit sensiblem Inhalt befinden, z.B. Dateien mit Datenbankverbindungsdaten. Generell wäre es zu empfehlen, derartige Includes erst gar nicht zu programmieren!

Wenn dennoch ein dynamischer Include erforderlich ist, so sollte man sich einer White-List bedienen:


$page = $GET['page'];

$availablePages = array('home', 'about', 'profile');

if (in_array($page, $availablePages)) {
  // Eingabeparameter korrekt
} else {
  // Fehlerbehandlung
}

Damit kann verhindert werden, dass durch einen falschen Eingabeparameter die Anwendung kompromittiert wird.

PHP Einstellungen

Man kann bereits mit der richtigen Konfiguration für eine erhöhte Sicherheit bei PHP sorgen. Hier ein paar Beispiele.

open_basedir

Durch setzen eines oder mehrere Verzeichnisse in der PHP Direktive open_basedir dürfen PHP-Skripte nur Dateien lesen und schreiben, die in diesen Verzeichnissen liegen. Dies erzeugt eine gewisse Sicherheit, indem einige Verzeichnisse vom programmatischen öffentlichen Zugriff geschützt werden (auf Betriebssystemebene ist der Zugriff immer noch möglich!). Mehrere Verzeichnisse werden durch Doppelpunkte getrennt.


open_basedir = /app:/app/lib
disable_functions

Diverse Systemfunktionen in PHP, mit denen externe Kommandos ausgeführt werden können, lassen sich mit der PHP Direktive disable_functions ausschalten. Neben System- und Prozesskontrollfunktionen, lassen sich auch ressourcenintensive Funktionen in PHP deaktivieren.


disable_functions = system, shell_exec, posix_setuid, pcntl_exec
disable_classes

Analog zu disable_functions lassen sich mit disable_classes die Verwendung bestimmter Klassen aus PHP-Extensions unterdrücken, um Sicherheitsprobleme zu vermeiden. Die Direktive erwartet eine kommaseparierte Liste von zu deaktivierenden Klassen.


disable_classes = mysqli, simplexml
max_execution_time

Die PHP Direktive max_execution_time legt fest, wie lange ein PHP-Skript ausgeführt werden kann, bevor ein Timeout ausgelöst wird. Damit wird vermieden, dass ein PHP-Skript nicht zu lange den Apache Webserver von anderen Aufgaben blockiert (oder das das Skript eines Angreifers unzählige Passworte am System testet!).

max_input_time

Entsprechend zur vorgenannten Direktive bestimmt max_input_time wie viel Zeit ein PHP-Skript maximal mit der Verarbeitung der Eingabe verbringen darf.


max_input_time = 30
memory_limit

Mit der PHP Direktive memory_limit ein Speicherlimit für ein PHP-Skript festlegen, damit es nicht den gesamten vorhandenen Speicher des Webservers belegen und damit andere Skripte oder Prozesse blockieren kann.


memory_limit = 128M
allow_url_fopen

Die PHP Direktive allow_url_fopen steuert die Übergabe von URLs an jede auf fopen() basierende PHP Funktion bzw. an jedes entsprechende Konstrukt, also include(), require(), etc.


allow_url_fopen = Off
allow_url_include

Möchte man nur die Konstrukte include, require, include_once, require_once einschränken, jedoch die fopen() Funktionen aktiviert belassen, so kann man hierzu die PHP Direktive allow_url_include deaktivieren.


allow_url_include = Off

Es geht in diesem Beitrag um PHP 7! Daher habe ich nicht mehr Einstellungen besprochen, die es schon seit PHP 5.4.0 nicht mehr gibt (register_globals, magic_quotes). Ferner bin ich auch nicht auf Suhosin eingegangen, weil es die Erweiterung für PHP 7 noch nicht gibt. Ich habe mich auf genau diejenigen Möglichkeiten beschränkt, welche die aktuelle Version von PHP 7.1.10 hergibt.

Es gibt noch viel mehr zu dem Thema zu sagen. Jedoch werde ich den Artikel für den Augenblick beenden. Da ich dem Thema IT Sicherheit zukünftig einen größeren Stellenwert in diesem Blog geben werde, folgen noch weitere Artikel, in denen ich darauf zurückkommen werde. Evtl. werde ich sogar diesen Artikel irgendwann noch erweitern.

Literatur

Ähnliche Artikel:

Fragen oder Feedback zu diesem Artikel

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert