Предотвращение обхода каталогов в PHP, но допускает пути - PullRequest
31 голосов
/ 17 ноября 2010

У меня есть базовый путь / любой / foo /

и $_GET['path'] должен быть относительно него.

Однако, как мне это сделать (чтение каталога), без разрешения каталогаОбход?

например.

/\.\.|\.\./

Не будет фильтровать должным образом.

Ответы [ 6 ]

107 голосов
/ 17 ноября 2010

Ну, одним из вариантов будет сравнение реальных путей:

$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!
}

По сути, realpath() разрешит указанный путь к фактическому жесткому физическому пути (разрешение символических ссылок, .., ., /, // и т. Д.) ... Поэтому, если реальный путь пользователя не начинается с реального базового пути, он пытается выполнить обход. Обратите внимание, что вывод realpath будет не иметь какие-либо "виртуальные каталоги", такие как . или .. ...

15 голосов
/ 25 ноября 2012

Ответ ircmaxell не был полностью правильным. Я видел это решение в нескольких фрагментах, но в нем есть ошибка, связанная с выводом realpath(). Функция realpath() удаляет конечный разделитель каталогов, поэтому представьте два смежных каталога, таких как:

/foo/bar/baz/

/foo/bar/baz_baz/

Так как realpath() удалит последний разделитель каталогов, ваш метод вернет "хороший путь", если $_GET['path'] будет равно "../baz_baz", поскольку это будет что-то вроде

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

Может быть:

$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!
}
4 голосов
/ 07 мая 2011

Недостаточно проверить наличие таких шаблонов, как ../ или подобных. Возьмите "../", например, который URI кодирует как "% 2e% 2e% 2f". Если ваша проверка шаблона происходит до декодирования, вы пропустите эту попытку обхода. Есть и другие хитрости, которые могут сделать хакеры, чтобы обойти проверку шаблона, особенно при использовании кодированных строк.

Я добился наибольшего успеха, остановив их, канонизировав любую строку пути к ее абсолютному пути, используя что-то вроде realpath (), как предполагает ircmaxwell. Только тогда я начинаю проверять обходные атаки, сопоставляя их с базовым путем, который я предопределил.

1 голос
/ 02 декабря 2014

Вы можете попробовать использовать regex для удаления всех ../s, но в PHP есть несколько хороших функций, которые сделают намного лучшую работу:

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

basename - удаляет всю информацию каталога из пути, например, ../pages/about.php станет about.php

realpath - возвращает полный путь к файлу, например about.php станет /home/www/pages/about.php, но только если файл существует.

В совокупности они возвращают только имя файла, но только если файл существует.

0 голосов
/ 05 июня 2019

1

поставить нулевой index.htm для блока -Index

2

фильтр sQS при запуске

// Path Traversal Attack
if( strpos($_SERVER["QUERY_STRING"], "../") ){
    exit("P.T.A. B-(");
}
0 голосов
/ 17 ноября 2010

Полагаю, вы имеете в виду, не позволяя пользователям проходить по каталогу, да?

Если вы пытаетесь помешать вашему PHP обходить каталог, вы просто должны заставить php работать правильно впервое место.

Чтобы остановить пользователей, вам нужен измененный файл .htaccess ...

Options -Indexes

(все это предполагает, что вы говорите о пользователях)

...