öffentlich
Redaktion Druckversion

PHP lernen (3): Interaktive Webseiten gestalten

Sicherheitsaspekte

Wir besprechen hier zunächst einige Sicherheitsaspekte theoretisch. Auch wenn Sie die beschriebenen Beispiele vielleicht noch nicht nachvollziehen können, behalten Sie das Thema Sicherheit von Anfang an im Kopf. Die Auswahl der Themen erhebt keinen Anspruch auf Vollständigkeit. Werden Sie sich der Problematik bewusst und versuchen Sie, Sicherheitslöcher zu umgehen. Die praktische Anwendung der vorgestellten Kniffe erfahren Sie in den Beispielen, die in den folgenden Abschnitten vorgestellt werden.

Wie eingangs erwähnt, sollten Sie Ihre dynamische Webseite so gut wie möglich vor unabsichtlich problematischen oder böswilligen Manipulationen schützen. Machen Sie sich zum Grundsatz, jeder Benutzereingabe zu misstrauen. Achten Sie darauf, dass externe Daten keine Variablen Ihres Skripts überschreiben können und dass die Variablen ausreichend geprüft werden, bevor sie in Ihr Programm übernommen werden. Generieren Sie aus Benutzereingaben niemals ungeprüft und automatisch eine Datenbankabfrage.

Externe Daten gelangen normalerweise über Formulare oder einen Querystring in die Skripte. Welche Gefahren dabei speziell bestehen und wie Sie diese leicht umschiffen, erfahren Sie in den beiden folgenden Abschnitten. Zum Abschluss werfen wir für das bessere Verständnis noch einen Blick auf das Referenzierungsmodell globaler Variablen bei PHP.

Sicherheitsrisiko Formulare

Besonders kritisch sind Formulare. Hier wird meist Inhalt eingegeben, der in einer Datenbank oder Datei permanent gespeichert wird. Ruft ein Dritter die Webseite auf, sieht er den generierten Inhalt. Dieses Prinzip gilt sowohl bei einem Redaktionstool als auch bei einem Gästebuch, Blog oder Forum. Beim Redaktionstool sollte man davon ausgehen, dass der Redakteur kein Interesse hat, die eigene Webseite zu zerstören. Dass das Tool ausreichend vor dem Zugriff Unbefugter geschützt sein muss, versteht sich von selbst.

Dennoch könnte auch ein Redakteur aus Unachtsamkeit in ein Textfeld etwas eintragen, was das Layout der Webseite zerstört. Gibt er beispielsweise ein öffnendes table-Tag ein, ohne es wieder zu schließen, kann die Anzeige der Tabellen der Webseite insgesamt durcheinander geraten.

Noch fataler sind die Folgen bei öffentlich zugänglichen Anwendungen wie Gästebüchern, Blogs oder Foren. Hier könnte mit JavaScript eine Umleitung eingetragen werden:

<script language="JavaScript" type="text/javascript">
location.href = "http://www.domain.com/fremde_seite.html";
</script>

Kommt nun ein Dritter auf Ihre Webseite und ruft diesen Gästebucheintrag auf, wird er sofort auf die fremde Seite umgeleitet.

Von der Konfiguration des Webservers ist abhängig, wie gefährlich Benutzereingaben werden können. In der php.ini gibt es mehrere Möglichkeiten, die Konfiguration abzusichern. Ist dort zum Beispiel die Option Magic Quotes eingeschaltet, ist es nicht ganz so leicht, in Programme einzubrechen, weil Sonderzeichen, die normalerweise in Code enthalten sind, automatisch maskiert werden. Es kann also sein, wenn Sie selbst versuchen, in Ihre Seite einzubrechen, dass Ihnen das aufgrund der Konfiguration des Webservers nicht gelingt. Darauf können Sie sich aber nicht verlassen. Außerdem schlafen Hacker auch nicht. Die weite Verbreitung von PHP macht es lohnenswert, verbreitete Schwachpunkte von PHP-Webseiten automatisch zu scannen und anzugreifen.

Die Lösung

Die Lösung ist recht einfach: Sie sollten die Eingabe jeder Form von Quellcode nach Möglichkeit verhindern. Dazu können Sie auf den eingegebenen Text vor jeder Weiterverarbeitung die Funktion strip_tags() anwenden und damit versuchen, alle HTML- und PHP-Tags ersatzlos zu entfernen. Alternativ können Sie mit html_entities() Sonderzeichen und damit auch spitze Klammern durch &lt; und &gt; ersetzen und unwirksam machen. Die Zeichen werden dann in der Ausgabe des Browsers (und damit im Gästebuch) zwar noch angezeigt, können aber keinen Schaden mehr anrichten.

Wollen Sie dem Benutzer dennoch die Möglichkeit geben, Formatierungen vorzunehmen, gehen Sie wie im vorangegangenen Kapitel beschrieben vor. Bieten Sie dem Redakteur vordefinierte Codes wie [rot]roter Text[/rot] an, die Zeichenkombinationen enthalten, die er sicher nicht in die Formularfelder eingeben will. Diese Codes wandeln Sie mit str_replace(); in gültige HTML-Tags um. Diesen Skriptschnipsel haben Sie in der "PHP lernen (2)" bei den foreach-Schleifen kennen gelernt. Gleichzeitig unterdrücken Sie wie eben beschrieben die Möglichkeit, im Formular direkt Code einzugeben. Wir werden das später praktisch umsetzen.

Soll dennoch HTML-Code in den Formularen zugelassen werden, seien Sie sich über das beschriebene Risiko für das Layout der Webseite bewusst. Sie nehmen auch in Kauf, dass Benutzer auf andere Webseiten umgeleitet werden können.

Wenn in einem Formular Dateien wie zum Beispiel Bilder hochgeladen werden können, ist besondere Vorsicht geboten, damit Ihnen keine böswilligen Skripte untergeschoben werden, die Ihre Webpräsenz oder noch schlimmer den gesamten Webserver mit vielen Webpräsenzen und Datenbanken gefährden können. Kontrollieren Sie mindestens die Dateiendung oder den MIME-Type der Datei, bevor Sie diese auf der Festplatte des Webservers speichern. Damit können Sie zwar nicht kontrollieren, was z. B. in einem Bild dargestellt wird, aber eine reine Skriptdatei können Sie immerhin abwehren. Wie Sie einen Dateiupload sichern, erfahren Sie weiter unten im Abschnitt Dateiupload.

Wenn Sie später einmal aus Formulardaten Datenbankabfragen generieren, übernehmen Sie die Daten nicht ungeprüft. Wenden Sie mindestens die Funktion mysql_real_escape_string(), um spezielle Zeichen innerhalb einer Zeichenkette für die Verwendung in einer SQL-Anweisung zu maskieren.

Sicherheitsrisiko Querystrings

Eine weitere Methode neben Formularen, Daten von Skript zu Skript weiterzureichen, besteht in der Übergabe per URL. Dabei hängen Sie an den URI mittels Fragezeichen einen sogenannten Querystring an:

http://www.domain.de/beispiel.php?variable=wert

Mit diesem Link wird die Datei beispiel.php aufgerufen. In dieser Datei steht nun die Variable mit Namen variable und dem Wert wert zur Verfügung. Sie sprechen die Variable über das Array $_REQUEST oder $_GET an. Sie können die Variablen in der Datei beispiel.php zum Beispiel so ausgeben:

<?php
print $_GET["variable"];    // Ausgabe: wert
?>

Einen Querystring erzeugen Sie zum einen direkt mit einem a-href-Link und auch, wenn Sie bei Formularen als Methode GET statt POST wählen. Dann werden alle Formulardaten sichtbar in der Adresszeile übertragen. Mehr zum Unterschied POST und GET bei Formularen unten bei den Formularen.

<a href="beispiel.php?variable=wert">Dies ist ein Link</a>
oder so:
<form action="beispiel.php" method="get"> ... </form>

Das gleiche Prinzip, das für Formulardaten gilt, gilt ebenso für Querystrings. Überprüfen Sie jede Variable, die über die Methode GET in Ihr Programm kommt, besonders gründlich. Besonders gründlich deshalb, weil die Manipulation des Querystrings besonders einfach ist. Jeder Benutzer sieht ihn in der Adresszeile seines Browsers offen vor sich und kann ihn ganz leicht manipulieren. Wenn dann auch noch Variablen eindeutig benannt und ihre Werte im Klartext übertragen werden, kann er auch leicht raten, was mit diesen Werten passieren soll. Ist er findig genug und verfügt über genügend kriminelle Energie, löscht er Ihnen die gesamte dahinter stehende Datenbank über einen ungenügend abgesicherten Querystring.

Im Abschnitt über Querystrings werden Sie anhand einiger Beispiele sehen, wann der Einsatz von Querystrings sinnvoll ist und wie sich eine solche Überprüfung leicht realisieren lässt.

Sessions und Cookies

Daten aus Sessions und Cookies zu manipulieren, ist nicht ganz so einfach. Dennoch sind auch solche Daten als extern zu bezeichnen, also ist auch hier ein wenig Vorsicht notwendig. Das bedeutet zum Beispiel, dass Sie niemals Zugangsdaten und Passwörter in Sessions oder Cookies speichern.

Was Sessions und Cookies sind und wie Sie einen Session basierten Passwortschutz programmieren, ohne die Zugangsdaten in einer Session oder einem Cookie abzulegen, lernen Sie im Abschnitt Sessionmanagement.

Globale Referenzierung von Variablen

Sämtliche Daten, die von außen in ein PHP-Skript übernommen werden können, werden von PHP automatisch erkannt und in Arrays geschrieben. Im oben vorgestellten Beispiel mit dem Querystring wird die Variable $_GET["variable"] von PHP automatisch zur Verfügung gestellt. In "PHP lernen (2)" wurden die Daten aus dem Passwortformular im Array $_REQUEST entgegengenommen.

Genauso funktioniert das bei Formularelementen, Sessions, Umgebungsvariablen usw., wie wir später noch sehen werden.

PHP schreibt diese Daten in sogenannte superglobale oder autoglobale Arrays. Die Arrays heißen $_GET für Variablen, die aus dem Querystring bzw. mit der Methode GET übernommen werden, $_POST für Variablen, die von einem Formular mit der Methode POST entgegengenommen wurden, $_FILES für Daten aus einem Dateifeld, $_SESSION für Variablen, die aus Sessions generiert werden, $_REQUEST für Variablen, die dem Skript über die GET-, POST- und COOKIE geliefert werden und $_SERVER für Variablen, die Informationen über den Server und den Client zur Verfügung stellen. In diesen Arrays werden die Werte als Elemente abgelegt und die Namen der Variablen als Schlüssel. In unserem Beispiel oben also ist variable als Name im Schlüssel des Arrays $_GET abgelegt und die jeweilige Wert im dazugehörigen Elements, hier wert.

In älteren Skripten, Tutorials oder Büchern zu PHP werden Sie vielleicht noch die direkte Entgegennahme von Variablen vorfinden. Auf unser gerade behandeltes Beispiel mit dem Querystring bezogen hieße das, dass die Variable $variable direkt verfügbar ist und nicht die umständlichere Schreibweise $_GET["variable"] benutzt wird. Genauso kann direkt auf den Attributnamen eines Formularfelds zugegriffen werden, ohne den Wert aus dem Array $_POST auszulesen. Diese Vorgehensweise funktioniert nur dann, wenn die Variablen global referenziert werden. Sie können dann allerdings auch nicht unterscheiden, ob $variable über einen Querystring oder aus einem Formular in Ihr Programm gekommen ist.

Der Umgang mit dem Speichern von externen Variablen, mit der sogenannten globalen Referenzierung von Variablen, wurde mit der Version PHP 4.1 verändert. Seit PHP 4.1 ist es möglich, in der php.ini den Eintrag register_globals auf off zu stellen. Dadurch wird die globale Referenzierung ausgeschaltet. Die ältere Syntax, die Variablen direkt mit z. B. $variable entgegennimmt, funktioniert dann nicht mehr. Diese Einstellung erzwingt eine größere Sicherheit in der PHP-Programmierung. Seit der Version PHP 4.2 steht dieser Wert bei der Installation automatisch auf off. Sie können ihn immer noch auf on schalten und damit alte Skripte laufen lassen.

Aus Sicherheitsgründen ist die alte Schreibweise unbedingt abzulehnen. Variablen auf ihre Herkunft zu prüfen, ist ein wesentliches Merkmal der Kontrolle entgegengenommener Variablen. Wenn Sie die Variablen direkt ansprechen, wissen Sie nicht, welchen Weg die Variable in Ihr Programm genommen hat, so können Ihnen per Querystring Variablen untergeschoben werden, die Sie eigentlich per POST aus einem Formular oder aus einer Session erwarten. Verwenden Sie in jedem Fall die superglobalen Arrays $_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_REQUEST und $_SESSION. Die Verwendung einiger dieser Arrays werden Sie in den nächsten Abschnitten an praktischen Beispielen kennen lernen.

Stellen Sie sicher, dass in Ihrem Testsystem die globale Referenzierung ausgeschaltet ist und zwingen Sie sich damit selbst, sicheren Code zu schreiben. Öffnen Sie dazu die php.ini, die wahrscheinlich in Ihrem Systemverzeichnis, z. B. c:/windows, liegt, in einem ASCII-Editor und suchen dort nach register_globals. Am Ende der Zeile sollte off stehen. Beachten Sie bei der Gelegenheit die Erläuterungen dazu im Kommentar der php.ini. Zur Erinnerung: In dieser Datei sind Kommentare durch ein Semikolon am Zeilenanfang gekennzeichnet.

Bei Providern ist die Registrierung oft noch auf on gestellt. Sie könnten also mit unsicher geschriebenem Code durchaus funktionsfähige Webseiten bauen. Früher oder später wird die Umstellung aber erfolgen. Deswegen und auch um einfach besseren Code zu schreiben, sollten Sie immer die superglobalen Arrays verwenden. Und Ihre Projekte werden auch bei der Umstellung der Provider ohne Probleme laufen!

Sollten Sie einmal in die Situation kommen, Code für eine PHP-Version kleiner als 4.1 schreiben zu müssen, achten Sie darauf, dass Sie z. B. statt des Arrays $_POST das Array $HTTP_POST_VARS benutzen. $_POST ist in den alten Versionen nicht bekannt. $HTTP_POST_VARS existiert aber bereits seit PHP 3 und ist in neueren Versionen noch verfügbar.

Um also abwärtskompatible Skripte zu schreiben, aber gleichzeitig das neue Sicherheitsmodell zu benutzen, kann auf die (älteren) superglobalen Arrays $HTTP_POST_VARS, $HTTP_GET_VARS, $HTTP_SERVER_VARS etc. zugegriffen werden. Damit schreiben Sie sicheren Code für Versionen älter als 4.1 und die neueren.

Mitglied werden, Vorteile nutzen!

  • Sie können alles lesen und herunterladen: Beiträge, PDF-Dateien und Zusatzdateien (Checklisten, Vorlagen, Musterbriefe, Excel-Rechner u.v.a.m.)
  • Unsere Autoren beantworten Ihre Fragen

Inhalt

Downloads zu diesem Beitrag

Newsletter abonnieren