2014-09-04 4 views
0

Я делаю простой сценарий файлового менеджера для своего сайта.Php scandir limit access

Для того чтобы перечислить все файлы и категории в папке, я использую функцию scandir(). У меня есть переменная, содержащая основной путь, например $path = /var/www/mysite/uploads. Тогда у меня есть функция, которая принимает переменную GET, содержащую дополнительный путь, например /my/photos/, поэтому я возвращаю содержимое /var/www/mysite/uploads/my/photos.

Проблема в том, что если пользователь отправит ../../../, что-то в этом роде, он поднимет дерево каталогов и сможет наблюдать за всей системой.

Как это можно ограничить? Единственное, что я гугле WHAS о chroot, но не уверен, если это то, что мне нужно

+0

Не позволяют пользователям иметь '' ../ на их входе, раздеть его, если они использовали это –

ответ

1

Вы можете использовать realpath():

$storagePath = "/var/www/mysite/uploads"; 
$path = $storagePath . $userPath; 

$path = realpath($path); 
if(strpos($path, $storagePath) === 0){ 
    //Path is okay 
    echo "Okay"; 
} 
else { 
    //User wants to gain access into a forbidden area. 
    echo "Danger"; 
} 

Live demo

Объяснение: Путь, указанный пользователем, является связавшись с дорогой хранения. Затем realpath используется для преобразования этого пути в absolute path. Если абсолютный путь начинается с пути хранения, все в порядке, иначе нет.

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

+0

Что вы думаете http://stackoverflow.com/questions/3661727/remove-dots-and-slashes-regex-non-relative об этом? используя ltrim? Фактически я составляю результирующий путь, как $ path = $ storagePath. $ UserPath; $ userPath не содержит/var/www/whatever, он содержит только часть пути, например/my/photos. Поэтому strpos не вернет true так или иначе. Но не уверен, достаточно ли решения с ltrim – Victor

+0

@Victor ltrim это точно, но я не думаю, что этого достаточно. Почему бы просто не заменить '$ _GET [" путь "]' в моем примере выше с '$ storagePath. $ userPath' (или '$ path'). Тогда он будет работать с 'strpos', не так ли? – idmean

+0

Если у меня есть путь = ../../../../.., то результирующий путь будет /var/www/mysite/uploads/../../../../, strpos возвращает true, когда находит/var/www/mysite/uploads в начале? – Victor

0

Вы всегда должны проверять входные данные пользователя! Сделайте регулярное выражение для проверки $ _GET ['path'].

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

0

Первый вопрос, на который вы должны ответить, - это то, почему вы принимаете с пользовательских путей.

После этого, если это действительно необходимо, вы должны защитить свой вход от абсолютных путей или использовать на нем ...

С чем-то вроде

$project_path = realpath($project_path); 
$realpath = realpath($user_input); 
if (str_pos($realpath, $project_path) !== 0) { 
    throw Exception('Security perimeter violation!'); 
} 
+0

Я принимаю путь, потому что если пользователь хочет изучить некоторые папки, ему нужно отправьте имя папки. И если папки включены друг в друга, это становится чем-то вроде «/ my/photos /», поэтому я предоставляю пользователю содержимое $ path. '/ My/photos /'.Я вижу, что вы и wumm оба используете realpath, спасибо за помощь, похоже, что мне нужно – Victor

+0

Отлично! По уважительной причине;) – mcuadros

Смежные вопросы