Sicheres Programmieren mit PHP (Teil 3)
In den ersten beiden Ausgaben der "Mitteilungen des URZ" 2004 haben wir bereits Hinweise zur sicherheitsbewussten PHP-Programmierung gegeben. In diesem Artikel soll nun die Upload-Funktion von PHP beleuchtet werden.
An dieser Stelle möchten wir die kleine Artikelserie (nachzulesen unter
http://www.tu-chemnitz.de/urz/www/php/secure.html) fortsetzen.
Denn "Sicheres Programmieren mit PHP" ist weiterhin ein brisantes Thema.
So gab es am 5.10.2004 eine
Warnung vom DFN-CERT (http://cert.uni-stuttgart.de/archive/win-sec-ssc/2004/10/msg00015.html),
in der eine massive Ausnutzung von Lücken in unsicher programmierten
PHP-Skripten beschrieben wird.
Und es waren auch WWW-Seiten im Campusnetz betroffen!
Auch bei diesem Angriff war das "blinde Vertrauen" in Daten von
externer Quelle (hier in der HTTP-Anforderung) die Schwachstelle.
Da bekanntlich Wiederholung die Mutter der Weisheit ist, stelle ich
den Merksatz aus dem letzten Artikel nochmals voran:
 |
Vertrauen Sie keinen Werten, die über Browsereingaben, den URL oder
Cookies in das PHP-Skript gelangen. Alle externen Parameter, selbst
wenn sie aus versteckten Feldern oder Auswahlmenüs kommen, müssen einer
Plausibilitätsprüfung unterworfen werden, bevor sie im Programm
verwendet werden.
|
Diese Tests und Überprüfungen sind mitunter aufwändig - Sicherheit hat
ihren Preis!
Im Folgenden wollen wir uns eine weitere, aus Sicht der Sicherheit kritische
"Einfallsmöglichkeit" für externe Daten näher ansehen.
Datei-Upload
PHP bietet Funktionen, mit denen sich ziemlich einfach ein Datei-Upload
(Hochladen von Dateien) vom WWW-Browser auf den WWW-Server realisieren lässt.
Eine Erklärung des nötigen HTML-Formulars und der PHP-Anweisungen finden Sie
in der
PHP-Dokumentation
(http://www.tu-chemnitz.de/docs/php/features.file-upload.html).
Hier folgt nur eine kritischer Ausschnitt - ein rudimentäres
HTML-Formular und das Kopieren einer
hochgeladenen Datei aus dem temporärem Bereich in das vorgesehene
Verzeichnis.
<form enctype="multipart/form-data" action="..." method="post">
<input name="datei" type="file" />
<input type="submit" value="Datei hochladen" />
</form>
<?php
$upload_verzeichnis = '/afs/tu-chemnitz.de/.../upload';
# Name für Upload-Element im Formular heißt 'datei'
if (isset($_FILES['datei']['name'])) {
$dateiname = $_FILES['datei']['name'];
# Dateinamen prüfen: Nur Buchstaben, Punkt, Unter- und Bindestrich erlaubt:
if (ereg('^[a-zA-Z0-9._-]*$', $dateiname)) {
# WICHTIG: Prüfen, ob Datei schon existiert, um Überschreiben zu verhindern!
if (file_exists("$upload_verzeichnis/$dateiname")) {
echo "Datei " . htmlspecialchars($dateiname) . " existiert schon!";
} else {
if (move_uploaded_file($_FILES['datei']['tmp_name'],
"$upload_verzeichnis/$dateiname")) {
echo "Ok";
} else {
echo "Fehler: " . $_FILES['userfile']['error'];
}
}
} else {
echo "Fehler: Ungültiger Dateiname " . htmlspecialchars($dateiname);
}
}
?>
Trotz dieser Vorsichtsmaßnahmen bietet ein solches Verfahren natürlich
ein "Einfallstor", über das auch unliebsame Dateien, etwa Schadprogramme,
in unser System gelangen können.
Deshalb sind gründliche Überlegungen und sorgfältige Progammierung
hinsichtlich der Sicherheit erforderlich.
Bieten Sie eine solche Upload-Möglichkeit möglichst nicht öffentlich
für jedermann an, sondern erlauben Sie das nur über eine Authentisierung
für Berechtigte.
Hinweise zum Zugriffsschutz über Anweisungen in der Datei .htaccess
finden Sie unter
Apache: Zugriffskontrolle
(http://www.tu-chemnitz.de/urz/www/access.html).
Es ist besonders auf das Verzeichnis zu achten, in das die
hochgeladene Datei geschrieben werden soll.
Da dieses Verzeichnis für den betreffenden WWW-Server schreibbar sein
muss, ist hier besondere Sorgfalt nötig:
- Verwenden Sie ein separates Verzeichnis,
in dem keine eigenen Dateien stehen.
- Stellen Sie nur die unbedingt erforderlichen AFS-Rechte ein, z.B.
dem WWW-Server
www-user.tu-chemnitz.de
nur das Listen und Einfügen neuer Dateien
erlauben (nicht aber das Lesen oder Überschreiben):
urz:www-user li
Außerdem müssen Sie sicherstellen, dass Dateien dieses Upload-Verzeichnisses
nicht direkt via WWW-Browser lesbar sind:
- Legen Sie das Verzeichnis am besten außerhalb Ihres WWW-Bereiches
(nicht unter
/afs/tu-chemnitz.de/www/root oder $HOME/public_html)
- Entfernen Sie das AFS-Leserecht für
system:anyuser und die
WWW-Server.
- Oder schützen Sie das Verzeichnis durch Anweisungen in der Datei
.htaccess
# Direkten Zugriff auf alle Dateien unterbinden
order deny,allow
deny from all
- Wenn Sie den lesenden Zugriff auf die hochgeladenen Dateien erlauben
müssen (etwa zum Austausch von Daten unter Berechtigten), müssen Sie
zumindest das Ausführen von CGI- oder PHP-Skripten unterbinden.
Dann schreiben Sie im
.htaccess
php_flag engine off
RemoveHandler .cgi
Sie sehen also auch hier, dass Sicherheit ihren Preis hat - die
Konfiguration ist ziemlich komplex.
Deshalb beraten wir Sie gern bei der Planung Ihrer WWW-Projekte.
Ein nachträgliches Ändern bestehender Projekte zur Erhöhung der
Sicherheit ist dagegen meist sehr schwierig und aufwändig.
Wenn Sie eine Upload-Fähigkeit für Ihr HOME-Verzeichnis brauchen
(oder für andere Verzeichnisse, für die Sie eine Schreibberechtigung haben),
können Sie auf eine fertige Lösung zurückgreifen:
Benutzen Sie den Web-basierten Datei-Manager WFM des Login-Servers:
https://login.tu-chemnitz.de/wfm/
Frank Richter, Oktober 2004