Защита от LFI-подобных уязвимостей, когда файл еще не существует

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

$path = realpath($_GET['path']);
// Protect against LFI vulnerabilities
if (substr($path, 0, strlen($root)) == $root)
{
    // safe
}

Однако realpath() работает только с файлами, которые уже существуют. Что, если я хочу убедиться, что место, куда пользователь собирается записать мой скрипт, находится в корневом каталоге?

Я не могу использовать realpath(), должен ли я просто проверить и удалить ссылки «..»? Или есть лучший способ?


person Chris Foster    schedule 25.07.2012    source источник
comment
Вы можете basename указать путь и проверить, находится ли он в корне. Я предполагаю, что ваши пользователи будут писать в существующий каталог загрузки или что-то в этом роде — если нет, то это, очевидно, не сработает.   -  person Waleed Khan    schedule 25.07.2012
comment
Приложение выдаст ошибку, если они попытаются записать в несуществующий каталог, поэтому можно с уверенностью предположить, что каталог будет существовать. Я знаю о basename, но не знаю, как это было бы полезно. Вы можете привести пример кода?   -  person Chris Foster    schedule 25.07.2012
comment
Упс, я имел в виду имя каталога: if (substr(dirname($path, 0, strlen($root)) == $root).   -  person Waleed Khan    schedule 25.07.2012
comment
Из документов: dirname() наивно работает с входной строкой и не знает о фактической файловой системе или компонентах пути, таких как «..», я также попробовал и убедился, что он не разрешает такие компоненты, как «..»   -  person Chris Foster    schedule 25.07.2012
comment
Если пользователь контролирует, в каком каталоге находятся файлы, вы можете просто удалить любые символы ../ из ввода и работать с этим. Если вы контролируете, в какой каталог они загружаются, просто проверьте допустимое имя файла — [a-z][A-Z][-_] должно быть все, что вы разрешаете, с предоставлением расширения. Делает вашу работу намного проще.   -  person Karthik Rangarajan    schedule 26.07.2012
comment
Да, к сожалению, я думаю, что это единственное решение. Если вы сделаете это как ответ, я выберу его, если ни у кого нет других идей. :)   -  person Chris Foster    schedule 26.07.2012


Ответы (1)


Как насчет проверки, находится ли realpath(dirname($file)) в корневом каталоге?

$dir = $path;
$found = false;

while ($dir) {
    $dir = dirname($dir);
    if (!is_dir($dir)) {
        continue;
    }

    if (strpos(realpath($dir), $root) === 0) {
        $found = true;
    }

    break;
}

var_dump($found);
person Gunther Konig    schedule 05.08.2012
comment
Кстати: ваш метод проверки возвращает true только тогда, когда $path == $root, поэтому я думаю, что это не очень правильно - person Gunther Konig; 05.08.2012