Является ли ASCII «../» единственной последовательностью байтов, которая указывает на обход каталога в PHP?

У меня есть приложение PHP, которое использует параметр $_GET для выбора файлов JS / CSS в файловой системе.

Если я отклоняю все запросы, в которых входная строка содержит ./ , \ или байт за пределами видимого 7-битного диапазона ASCII, это достаточно для предотвращения прохождения родительских каталогов при передаче пути к базовым (на основе C) файлам PHP ?

Я знаю об уязвимостях с нулевым байтом , но есть ли какие-либо другие альтернативные / искаженные символы кодирования, которые могут скрипеть этими проверками?

Вот основная идея (не производственный код):

 $f = $_GET['f']; // eg "path/to/file.js" // goal: select only unhidden CSS/JS files within DOC_ROOT if (! preg_match('@^[\x20-\x7E]+$@', $f) // outside visible ASCII || false !== strpos($f, "./") // has ./ || false !== strpos($f, "\\") // has \ || 0 === strpos(basename($f), ".") // .isHiddenFile || ! preg_match('@\\.(css|js)$i@', $f) // not JS/CSS || ! is_file($_SERVER['DOCUMENT_ROOT'] . '/' . $f)) { die(); } $content = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/' . $f); 

Обновление: мой вопрос действительно о том, как функции файловой системы C интерпретируют произвольные последовательности ASCII (например, если есть недокументированные escape-последовательности), но я понимаю, что это, вероятно, зависит от системы и, возможно, является неосуществимым на практике.

Для моей активной проверки дополнительно требуется, чтобы realpath($fullPath) начинался с realpath($_SERVER['DOCUMENT_ROOT']) , гарантируя, что файл находится в пределах DOC_ROOT, но целью этого сообщения было то, что он должен realpath() (он оказался ненадежным в в разных средах), но при этом допускают необычные, но допустимые URI, такие как /~user/[my files]/file.plugin.js .

Solutions Collecting From Web of "Является ли ASCII «../» единственной последовательностью байтов, которая указывает на обход каталога в PHP?"

Вы сами это упоминаете, но сравнение realpath пути ввода с известным корнем – лучшее решение, о котором я могу думать. Realpath разрешит любые скрытые функции пути / файловой системы, включая символические ссылки.

При фильтрации входных данных для обеспечения безопасности всегда используйте «белые списки», а не переклички.

Вы должны отклонять все пути, которые не соответствуют /^([A-Za-z0-9_-]+\/?)*[A-Za-z0-9_-]+\.(js)|(css)?$/ .

Это позволит допускать нормальные сегментированные пути, где каждый сегмент имеет буквы, цифры или _- .

Может потребоваться небольшая перестройка, но даже если вы ../../passwd , basename() будет изолировать ее. Затем вы можете поместить все файлы, которые хотите использовать в одной папке.

Учитывая ../../././././a/b/c/d.txt , basename($f) будет d.txt ; этот подход кажется мне более мудрым, вместо того, чтобы пытаться перехитрить пользователя и забыть о дыре.