Предотвращение обхода каталога в PHP, но допускающие пути

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

и $_GET['path'] должен относиться к нему.

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

например.

 /\.\.|\.\./ 

Не будет правильно фильтроваться.

Solutions Collecting From Web of "Предотвращение обхода каталога в PHP, но допускающие пути"

Ну, один из вариантов – сравнить реальные пути:

 $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 не будет никаких «виртуальных каталогов», таких как . или …

Ответ 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! } 

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

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

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

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

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

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

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

Я предполагаю, что вы имеете в виду, не позволяя пользователям перемещаться по каталогу да?

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

То, что вам нужно, чтобы остановить пользователей, – это модифицированный файл .htaccess …

 Options -Indexes 

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