it-swarm.com.de

Verzeichnis Traversal in verhindern PHP aber Pfade zulassen

Ich habe einen Basispfad/was auch immer/foo /

und $_GET['path'] sollte relativ dazu sein.

Wie mache ich das (Lesen des Verzeichnisses), ohne das Durchsuchen von Verzeichnissen zuzulassen?

z.B.

/\.\.|\.\./

Filtert nicht richtig.

30
Johnny

Nun, eine Möglichkeit wäre, die realen Pfade zu vergleichen:

$basepath = '/foo/bar/baz/';
$realBase = realpath($basepath);

$userpath = $basepath . $_GET['path'];
$realUserPath = realpath($userpath);

if ($realUserPath === false || strpos($realUserPath, $realBase) !== 0) {
    //Directory Traversal!
} else {
    //Good path!
}

Grundsätzlich löst realpath() den angegebenen Pfad in einen tatsächlichen harten physischen Pfad auf (Auflösen von Symlinks, .., ., /, // usw.) ... Wenn also der tatsächliche Benutzerpfad nicht mit dem tatsächlichen Basispfad beginnt, es versucht eine Durchquerung zu machen. Beachten Sie, dass die Ausgabe von realpath nicht "virtuelle Verzeichnisse" wie . oder ..... enthält.

105
ircmaxell

die Antwort von ircmaxell war nicht ganz richtig. Ich habe diese Lösung in mehreren Ausschnitten gesehen, aber sie hat einen Fehler, der mit der Ausgabe von realpath() zusammenhängt. Die Funktion realpath() entfernt das nachfolgende Verzeichnistrennzeichen. Stellen Sie sich zwei zusammenhängende Verzeichnisse vor:

/foo/bar/baz/

/foo/bar/baz_baz/

Da realpath() das letzte Verzeichnistrennzeichen entfernen würde, würde Ihre Methode "guten Pfad" zurückgeben, wenn $_GET['path'] gleich "../baz_baz" wäre, da dies in etwa der Fall wäre

strpos("/foo/bar/baz_baz", "/foo/bar/baz")

Könnte sein:

$basepath = '/foo/bar/baz/';
$realBase = realpath($basepath);

$userpath = $basepath . $_GET['path'];
$realUserPath = realpath($userpath);

if ($realUserPath === false || strcmp($realUserPath, $realBase) !== 0 || strpos($realUserPath, $realBase . DIRECTORY_SEPARATOR) !== 0) {
    //Directory Traversal!
} else {
    //Good path!
}
14

Es reicht nicht aus, nach Mustern wie ../ oder dergleichen zu suchen. Nehmen Sie beispielsweise "../" an, dessen URI zu "% 2e% 2e% 2f" kodiert. Wenn Ihre Musterprüfung vor einer Dekodierung erfolgt, würden Sie diesen Durchlaufversuch verpassen. Es gibt einige andere Tricks, mit denen Hacker eine Musterprüfung umgehen können, insbesondere bei der Verwendung codierter Zeichenfolgen.

Ich hatte den größten Erfolg, wenn ich sie stoppe, indem ich jeden Pfadstring mit etwas wie realpath () kanonisiert habe, wie ircmaxwell vermuten lässt. Erst dann suche ich nach Durchquerungsangriffen, indem ich sie mit einem von mir vordefinierten Basispfad abgleichen.

4
Cowlby

Sie könnten versucht sein, regex zu verwenden, um alle ../s zu entfernen, aber in PHP gibt es einige Nice-Funktionen, die eine viel bessere Arbeit leisten werden:

$ page = Basisname (realpath ($ _ GET));

basename - Entfernt alle Verzeichnisinformationen aus dem Pfad, z. ../pages/about.php würde zu etwa.php werden

realpath - gibt einen vollständigen Pfad zur Datei zurück, z. about.php würde zu /home/www/pages/about.php werden, aber nur, wenn die Datei existiert.

Zusammen geben sie nur den Dateinamen zurück, aber nur, wenn die Datei existiert. 

1
L4m0r

1

geben Sie für den -Index-Block eine leere index.htm ein

2

filter sQS beim Start

// Path Traversal Attack
if( strpos($_SERVER["QUERY_STRING"], "../") ){
    exit("P.T.A. B-(");
}
0
Lo Vega

Ich nehme an, Sie meinen, ohne users zu erlauben, das Verzeichnis ja zu durchqueren?

Wenn Sie versuchen, Ihr eigenes PHP vom Durchsuchen des Verzeichnisses abzuhalten, sollten Sie den PHP-Code erst richtig funktionieren lassen.

Was Sie benötigen, um Benutzer zu stoppen, ist eine geänderte .htaccess-Datei ...

Options -Indexes

(Dies alles setzt voraus, dass Sie über Benutzer sprechen.)

0
J V