Предотвращение обхода каталога с помощью веб-приложения - являются ли регулярные выражения пуленепробиваемыми?

Я нахожусь в ситуации, когда мне нужно разрешить пользователю загружать файл, динамически определяемый по URL. Перед началом загрузки мне нужно выполнить некоторую аутентификацию, поэтому загрузка должна сначала пройти через скрипт. Все файлы будут храниться вне веб-корня, чтобы предотвратить загрузку вручную.

Например, любое из следующего может быть ссылками на скачивание:

По сути, глубина папки может варьироваться.

Чтобы предотвратить обратный путь в каталогах, например, скажем: http://example.com/etc/passwd Мне нужно, очевидно, провести некоторую проверку URI. (Примечание: у меня нет возможности хранить эту информацию в базе данных, должен использоваться URI)

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

preg_match('/^\/([-_\w]+\/)*[-_\w]+\.(zip|gif|jpg|png|pdf|ppt|png)$/iD', $path)

Какие еще есть варианты, чтобы убедиться, что URI нормален? Возможно использование realpath в PHP?

6 ответов

Я бы порекомендовал использовать realpath() превратить путь в абсолют. Затем вы можете сравнить результат с путями к разрешенным каталогам.

Я не PHP-разработчик, но могу вам сказать, что использование защиты на основе Regex для такого сценария похоже на ношение футболки от урагана.

Этот тип проблемы известен как уязвимость Canonicalization на языке безопасности (когда ваше приложение анализирует заданное имя файла до того, как ОС сможет преобразовать его в свой абсолютный путь к файлу). Злоумышленники смогут найти любое количество изменений имени файла, которое почти наверняка не будет соответствовать вашему регулярному выражению.

Если вы должны использовать Regex, сделайте его как можно более пессимистичным (сопоставляйте только действительные имена файлов, отклоняйте все остальное). Я бы посоветовал вам немного изучить методы канонизации в PHP.

Я думаю, что следующие 3 проверки могут быть идеальным решением

  • Убедитесь, что файл соответствует общепринятому регулярному выражению того, как может выглядеть путь к файлу
  • Используйте realpath (в PHP), чтобы получить каноническую форму запрошенного пользователем файла и сравнить его, чтобы убедиться, что он находится в базовом каталоге.
  • Начиная с PHP v5.3, вы можете использовать ini_set, чтобы ограничить open_basedir определенной папкой, так что файлы вне этой папки не могут быть прочитаны (с fopen, include, fread и т. Д.)

Я думаю, что вы могли бы использовать htaccess для этого.

Какие символы будут содержать ваши имена файлов? Если это просто [a-zA-Z0-9] пунктирные и косые черты из одной точки, то не стесняйтесь снимать что-либо еще.

Мое решение

$filesPath = realpath(".");
$reqPath = realpath($_GET["file"]);
$pat = "%^".preg_quote($filesPath)."%";

if(preg_match($pat,$reqPath)){
    echo "File found";
}else{
    echo "Access denied"
}
?>
Другие вопросы по тегам