PHP realpath не работает для предотвращения обхода каталога

Я получил чужой код для системы, которая показывает папки с фотографиями в вашем браузере.

Например, это возможный URL-адрес на сайте:

gallery.php?action=view&folder=Cars

На данный момент вы можете заменить «Cars» на ../../../../../, что с радостью покажет корневую папку Linux. К счастью, на данный момент сайт не работает.

Я попытался использовать realpath, чтобы исправить это. Вот что у меня есть до сих пор:

case 'view' :
$name = realpath(dirname(__FILE__) . "/Content/Gallery/" . $_GET['folder']);

echo $name;

$data = $file->getPictures($name);
require 'Views/Gallery.view.php';
break;

Я добавил эхо в третью строку, чтобы увидеть, каким будет URL-адрес. В приведенном выше URL-адресе все в порядке, и эхо выводит это:

/var/www/Content/Gallery/Cars 

Все идет нормально. Однако, если я ввожу /../../../../../../../../ вместо «Cars», $name становится / и на странице по-прежнему отображается корневая папка. Английский не мой родной язык, поэтому я могу неправильно понять, как работает realpath или что он делает. Насколько я понял, он удаляет любой экземпляр ../ с заданного URL-адреса.

Может кто-нибудь, пожалуйста, скажите мне, что я делаю неправильно?


person yesman    schedule 08.01.2014    source источник
comment
возможный дубликат Предотвращение обхода каталога в PHP, но разрешение путей   -  person Patrick Q    schedule 09.01.2014
comment
Вот почему PHP получает плохую репутацию :\   -  person Mike B    schedule 09.01.2014
comment
@Майк почему? realpath() не предназначен для борьбы с атаками обхода каталога; и не претендует на это   -  person Pekka    schedule 09.01.2014
comment
@Pekka웃 Люди продолжают увековечивать эти ужасные сценарии. Я удивлен, что здесь нет mysql_query($_GET['sql']);...   -  person Mike B    schedule 09.01.2014
comment
@Майк, да, это правда.   -  person Pekka    schedule 09.01.2014


Ответы (2)


Насколько я понял, он удаляет любой экземпляр ../ с заданного URL-адреса.

Нет, это не то, что он делает. Это не для URL-адресов, это для путей. Он просто преобразует путь и расширяет ../ в нужную папку. Он не удаляет их, он разрешает их, то есть вычисляет, что означает ../, и изменяет путь, чтобы иметь это.

Он также заменяет / на \ в Windows.

реальный путь

realpath() расширяет все символические ссылки и разрешает ссылки на '/./', '/../' и дополнительные символы '/' во входном пути и возвращает канонизированный абсолютный путь.

person Jessica    schedule 08.01.2014
comment
Спасибо, меня смутил пример на этой странице. Там пример выводит echo realpath('./../../etc/passwd'); как /etc/passwd. Как тогда остановить обход каталога? - person yesman; 09.01.2014
comment
Прочтите пример еще раз. Перед этим он перемещается в каталог. Относительно этого каталога './../../etc/passwd' можно преобразовать в /etc/passwd - person Jessica; 09.01.2014

Одного realpath() недостаточно для борьбы с обходом каталогов.

То, что вы описываете, это именно то, для чего он предназначен: он переводит относительные вещи, такие как ../, в фактический путь к каталогу.

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

 $name = realpath(dirname(__FILE__) . "/Content/Gallery/" . $_GET['folder']);

 // The safe root directory. 
 $safe_root = dirname(__FILE__) . "/Content/Gallery/";

 // Check whether realpath() result is still inside /Content/Gallery
 if (substr($name, 0, strlen($safe_root)) != $safe_root) 
   die ("Possible directory traversal attack");
person Pekka    schedule 08.01.2014