Server-Schutz

Sicherheitslücken in PHP absichern

20.2.2013 von Stephan Lamprecht

Mit PHP lassen sich tolle Anwendungen programmieren. Leider gerät die Programmiersprache aber auch immer wieder wegen Sicherheitslücken in die Schlagzeilen.

ca. 7:45 Min
Ratgeber
VG Wort Pixel
internet, webdesign, sicherheit, php, server, sql, variable
internet, webdesign, sicherheit, php, server, sql, variable
© Internet Magazin

Natürlich will jeder Programmierer möglichst schnell seine Anwendung umsetzen und sie auf dem Server zur Verfügung stellen. Gedanken zur Sicherheit stehen dabei üblicherweise nicht im Vordergrund.Und nicht immer ist auch gleich offensichtlich, dass der gerade geschriebene Code eine Sicherheitslücke bedeutet. Dabei lassen sich viele Hacking-Versuche durch einfache Maßnahmen und etwas mehr Arbeit leicht verhindern.

Nutzereingaben validieren

Im Quelltext vieler Programme ist ein geradezu grenzenloses Vertrauen gegenüber dem Anwender spürbar. Er darf in Formulare eingeben, was er will. Bösartige Nutzer oder Hacker scheint es in der Welt dieser Entwickler nicht zu geben.Hüten Sie sich davor, den gleichen Fehler zu machen und trauen Sie niemals Nutzereingaben, die Sie nicht selbst validiert haben. Nehmen Sie als Beispiel ein Formular, in dem die Nutzer das eigene Geburtsdatum eintragen können. Natürlich könnten Sie einfach jegliche Eingabe abfangen und dann weiterverarbeiten.Deutlich sicherer (wenn auch mit höherem Aufwand) ist die Validierung der Eingabe gegenüber erlaubten Zeichen. In diesem Beispiel erwarten Sie also die Angaben zum Tag in zweistelliger Form mit Werten zwischen 1 und 31. Die Angabe des Monats mit Werten zwischen 1 und 12 und schließlich eine vierstellige Jahresangabe.Ihr wichtigster Begleiter sind dabei reguläre Ausdrücke. Sofern Sie sich damit noch nicht beschäftigt haben, holen Sie dies am besten schleunigst nach. Quellen und Tutorials gibt es dazu im Internet genügend.Zunächst wird das Finden des passenden regulären Ausdrucks etwas schwierig sein. Ist dieser aber gefunden und liefern Sie eine passende Fehlermeldung für den Anwender zurück, räumen Sie SQL-Injektionen wenig Raum ein.Überprüfen Sie also bei allen Eingaben des Nutzers in Form von POST oder GET die erlaubten Zeichen, die Länge der Eingabe, den Zahlenraum bei Zifferneingaben. Eine Validierung für das genannte Beispiel könnte so aussehen:

if ( ! preg_match( "/^[0-9]{ 1,2}
$/", $_GET['tag'] ) )
{
// Fehlermeldung
}
if ( ! preg_match( "/^[0-9]{ 1,2}
$/", $_GET['monat'] ) )
{
// Fehlermeldung
}
if ( ! preg_match( "/^[0-9]{ 4} $/",
$_GET['jahr'] ) )
{
// Fehlermeldung
}

PHP bleibt PHP

Nicht immer werden Sie als Programmierer eines Skripts auch auf die Konfiguration des Webservers Einfluss haben. Ist dieser fehlerhaft eingerichtet, ist es durchaus möglich, dass ein Nutzer sich den Inhalt von Verzeichnissen ansehen kann.Darunter dann auch die Dateien und Ordner Ihrer PHP-Anwendung. Der Browser selbst zeigt indes kommentarlos jede Datei an, die als reiner Text einzusehen ist. Angenommen Sie lagern die Zugangsdaten zur Datenbank einer Anwendung in einer Konfigurationsdatei ab, die der Nutzer an seine Gegebenheiten anpassen kann. Gar nicht selten ist etwa:

<?php
/*
Datenbank-Details
*/
$db_host = 'localhost';
$db_user = 'beispiel';
$db_pass = 'geheim';
$db_name = 'meine_anwendung';
...

Sind diese Informationen in der Datei config.inc gespeichert, und der Nutzer kann mit dem Browser zu dieser Datei navigieren, wird sie auch ohne Probleme mit allen diesen Details eingeblendet werden. Deswegen vergeben Sie allen Ihren Projektdateien die Endung php.Sind Sie auf solche Eingaben der Nutzerkonfiguration angewiesen, suchen Sie nach einem Weg, diese einmalig einzulesen und an anderer Stelle in Ihren Programmdateien maskiert abzuspeichern.

Verzeichnis-Browsen verbieten

Um die Auflistung des Verzeichnisinhalts zu unterbinden, können Sie die .htaccess-Datei des Servers bearbeiten. Oder Sie liefern bei der Installation Ihrer Anwendung eine eigene .htaccess mit aus, die die Option -Indexes enthält.Eine Variante ist, in jeden Ordner eine leere Datei mit index.html abzulegen. Da die meisten Server so konfiguriert sind, dass diese Datei dargestellt wird, wenn ein Verzeichnis aufgerufen wird, kann der Nutzer von dort mit dem Browser nicht weiter.

Cross Site Scripting vermeiden

Nach wie vor ein Problem ist das sogenannte Cross Site Scripting. Nur weil sich einige moderne Browser weigern, entsprechenden Code auszuführen, bedeutet dies nicht, dass Sie Ihren Quellcode nicht gegen diese Angriffsversuche härten sollten.Nehmen wir an, der Nutzer kann im Adressfeld des Browsers einen Funktionsaufruf finden, wie search.php?term=haus. Wäre er jetzt bösartig, könnte er versuchen, diese Eingabe vorzunehmen: http://www.website.com/search.php?term=<script>alert('doof');</script>. Es soll an dieser Stelle jetzt nicht noch mehr ins Detail gegangen werden, was mit dieser Angriffstechnik alles möglich ist.Es gibt generell verschiedene Möglichkeiten, um HTML-Elemente (und dazu gehören ja auch Aufrufe von Javascript) durch den Nutzer zuzulassen, zugleich aber etwas für die Sicherheit zu tun. Eine Option besteht darin, auf die recht populäre Bibliothek HTML_BBCodeParser auszuweichen, deren Implementierung gut erklärt ist.Sie finden eine Version unter pear.php.net. Diese erlaubt in Benutzereingaben nur ein bestimmtes Set aus Auszeichnungsoptionen, die dann später in HTML umgewandelt werden.Der Nutzer selbst muss etwa [b]Fett[/b] in das Formular eingeben, um eine fett hervorgehobene Passage zu erzeugen. Gefährlichere Aufrufe sind damit indes nicht möglich.Der zweite Weg besteht darin, jede Rückgabe des Benutzerinputs zu maskieren. Um etwa das Suchergebnis auf die oben gezeigte Eingabe sicher zurückzugeben, könnten Sie sich der Funktion htmlentities bedienen. Dies sähe dann als Code-Fragment etwa so aus:

<?php
$term = $_GET['term'];
?><html><body>
Ihre Suche nach : <?php echo
htmlentities($term); ?></body></html>

Deaktivieren Sie "böse" PHP-Komponenten!

Wenn Sie es noch nicht getan haben, schalten Sie in der Einstellungsdatei von PHP unbedingt die Option Register Globals aus. Viele Hoster verbieten deren Verwendung ohnehin. Bei einem eigenen Root-Server müssen Sie sich indes selbst darum kümmern. Eigentlich ist die Funktion für die schnelle Entwicklung von PHP-Anwendungen eine tolle Möglichkeit.Ein Aufruf einer URL nach dem Schema http://ihre_seite.tld/index.php?var=1 würde bei eingeschalteter Funktion ermöglichen, direkt auf den Wert der Variablen mittels $var zuzugreifen. Sie müsste also nicht erst definiert werden. Unglücklicherweise kann diese Option nicht wahlweise aktiviert werden. Mit anderen Worten kann jeder Angreifer beliebige Variablen an jedes Skript senden, dessen Namen er kennt oder nur erahnt.Rufen Sie zur besseren Absicherung die Datei php.ini Ihrer Installation auf und setzen Sie dort explizit das Statement register_globals = Off. Oder Sie setzen ganz auf die Datei .htaccess und fügen dort php_flag register_globals 0 ein.Sinngemäß gilt dies auch für die an und für sich sinnvolle Funktion der Magic Quotes. Diese maskiert eigentlich alle von außen an ein Skript übergebenen Textfragmente und setzt vor diese einen Backslash. Bei eingeschalteter Funktion würde aus "Hallo Welt" ein \ "Hallo Welt\".Der Mechanismus ist aber nicht hinreichend genug als Schutz gegen SQL-Injektionen, zum anderen schafft ein Skript unnötige Probleme, wenn Sie sich auf aktivierte Magic Quotes verlassen, es aber auf einer anderen Serverumgebung ausführen. Deswegen am besten in der php.ini ausschalten:

; Magic quotes für GET/POST/Cookie
Daten
magic_quotes_gpc = Off
; Magic quotes für Daten aus SQL
magic_quotes_runtime = Off
magic_quotes_sybase = Off

Während der Entwicklung eines Skripts kann die automatische Darstellung aller Fehler direkt auf dem Bildschirm hilfreich sein. Sie erhalten damit eine Rückmeldung, wenn es für den auftretenden Fehler keine Pufferung und Ausgabe einer individuellen Fehlermeldung gibt.Auf einem Produktivsystem schalten Sie in der php.ini aber unbedingt den Wert display_errors = Off. Denn hier haben die geschwätzigen Rückmeldungen aus Sicherheitsgründen nichts zu suchen.

SQL-Injektionen vorbeugen

SQL-Injektionen gehören sicherlich zu den bekannteren Sicherheitslücken in Anwendungen. Regelmäßig ist von ihnen im Zusammenhang mit Problemen die Rede. SQL-Injektionen können immer dann auftreten, wenn Argumente und Daten, die an die Datenbank übergeben werden, ungeprüft weitergereicht werden.Verringern können Sie dieses Risiko durch die Verwendung des PHP-Moduls MySQLi. Mit der Funktion mysqli_ real_escape_string können Sie das Datenbankkommando maskieren. Um etwa aus der Tabelle mitglieder einen Benutzernamen auszulesen, wäre der Funktionsaufruf etwa so:

$username = mysqli_real_escape_
string( $GET['username'] );
mysql_query( "SELECT * FROM
mitglieder WHERE username = '".
$username."'");

Eine andere Option sind sogenannten Prepared Statements. Diese können SQL-Injektionen wirkungsvoll verhindern, weil vor Ausführung des Datenbank-Kommandos die übergebenen Parameter überprüft werden. Rein funktional schickt eine solche vorbereitete Abfrage diese zunächst an den Server, wo sie validiert wird.Die Abfrage enthält an den Stellen, wo Sie Variablen auslesen oder übergeben wollen, Platzhalter. Diese lösen Sie dann später auf und übergeben sie an das Statement. Erst dann werden die Variablen in die Datenbank geschrieben. Das sieht dann etwa so aus:

// Statement Objekt erzeugen
$stmt = $db->stmt_init();
// Statement vorbereiten
$stmt = prepare( "SELECT * FROM
mitglieder WHERE id = ?" );
// Statement an Parameter binden.
Wert i steht fuer Integer
$stmt->bind_param( "i", $id );
// Statement ausfuehren
$stmt->execute();

In diesem Beispiel können Sie die Datenbank abfragen, wobei Sie das Feld id berücksichtigen. Genutzt wird dann innerhalb des Statements die Variable $id. Auch wenn die geschilderten Methoden gut geeignet sind, um SQL-Injektionen nahezu auszuschließen, sollten Sie sich dennoch überlegen, ob Sie die Gültigkeit von Variablen und Parametern nicht zusätzlich durch entsprechende Schleifen überprüfen.

Referenzen außerhalb der Webdokumente ablegen

Generell liegen alle Dokumente, die extern über den Webserver erreichbar sein sollen, im Verzeichnis /var/www. In diesem Ordner müssen auch alle PHP-Dateien liegen, die über den Browser aufgerufen werden.Dies gilt allerdings nicht für andere Dateien. Egal ob es nun Grafiken oder andere Ressourcen sind (zum Beispiel auch die Parameter für die Datenbank-Verbindung), sie können außerhalb dieser Hierarchie gespeichert werden.Wenn Sie diese also in ein Verzeichnis unter /var/<verzeichnis> verlagern, können diese von außen nicht mehr erreicht werden. Selbst wenn das Browsing für Verzeichnisse aktiviert sein sollte.

Achten Sie auf den Datenbanknutzer!

Wer mit seiner PHP-Anwendung auf eine Datenbank zugreift, um deren Inhalte zu verändern oder auszulesen, tut dies über einen Datenbanknutzer. Im Backend der Datenbank sollten die Rechte dieses Nutzers geprüft und nach Möglichkeit soweit wie möglich beschränkt werden.Die Privilegien, Datenbankkommandos auszuführen, sind meist genauso überflüssig, wie auf das Dateisystem des Servers zuzugreifen. Die Erlaubnis file_priv etwa darf dem Datenbanknutzer, mit dem Ihr Skript kommuniziert, besser nicht zugewiesen werden, um den Zugriff auf das lokale Dateisystem zu vermeiden.

Sichern Sie Ihre Variablen!

Um zu vermeiden, dass Variablen durch die Eingabe des Benutzers bereits verwendet werden können, bevor sie eigentlich zum Einsatz kommen, sollten Sie diese vorab definieren und einen Wert zuweisen. Sichern Sie deshalb alle Variablen, die Sie global in Ihren Skripten benötigen, dadurch ab, dass Sie ihnen einen Wert zuweisen.

$logged_in = 0; oder $guest=0

Wichtig ist dies immer dann, wenn durch diese Bedingung oder Variable etwa der Zugriff auf einen Inhalt definiert wird. Schließlich wollen Sie den Nutzer ja nicht jedes Mal erneut zur Eingabe seines Passwortes auffordern, sondern den Zustand zwischenspeichern.Dieser Artikel konnte längst nicht alle potenziellen Schwachstellen in der Entwicklung von PHP-Skripten abdecken. Aber wenn Sie beim Programmieren unsere Tipps beherzigen, haben Sie bereits viel für die Sicherheit der Anwendungen beigetragen.

Mehr lesen

Chronologische Liste und Netflix-Links

Marvel-Filme- und -Serien: Das ist die richtige Reihenfolge

Neuerscheinungen in der Übersicht

Netflix: Neue Filme und Serien

Vorschau auf Film- und Serien-Highlights

Amazon Prime Video: Neuheiten

Weiter zur Startseite  

Mehr zum Thema

internet, apple, safari, web-apps, ios, remote debugging, tipps, tricks

Tipps & Tricks

Remote Debugging mit Safari Web Inspector

Wie Sie mit dem Safari-Browser schnell Webseiten und Web-Apps auf iOS debuggen können, zeigen wir Ihnen.

internet, webdesign, responsive webdesign, Performance, optimierung

Responsives Webdesign

Mehr Performance fürs Responsive Webdesign

Trotz aller Verzüge gibt es auch einen Schwachpunkt beim Responsive Webdesign: Die Performance ist oft schlecht, da dieselben Ressourcen für…

internet, webdesign, adobe,  Illustrator, CS6

Webdesign

Webdesign in Adobe Illustrator CS6

Adobe Illustrator wird im Webdesign immer beliebter. Wie Sie das Tool richtig einsetzen, erfahren Sie hier.

Facebook stellte die neue Suche

Facebook

Facebooks Social Graph Search

Was sind die Implikationen für Unternehmen und Endanwender bei Facebooks neuer Suche Graph Search?

Der BGH erklärt das Internet zur Lebensgrundlage.

Online-Recht

Darauf müssen Sie bei den AGB achten

Allgemeine Geschäftsbedingungen liest sich niemand gerne durch. Sie sind jedoch notwendig und äußerst sinnvoll. Worauf sie achten sollten.