PHP Include на основе REQUEST_URI

Существуют ли какие-либо риски безопасности при использовании $_SERVER['REQUEST_URI'] для включения файла? Можете ли вы пройти ../../.. через запрос uri?

Я думаю, что-то вроде этого:

 <?php $path = $_SERVER['REQUEST_URI']; $path = preg_replace('~\\.html?$~', '.php', $path); include $path; ?> 

Это должно заменить URI «.htm» или «.html» для путей «.php» и визуализировать их. Но я беспокоюсь о безопасности здесь.

$_SERVER['REQUEST_URI'] содержит запрошенный путь и строку запроса URI, как он появился в строке запроса HTTP . Поэтому, когда запрашивается http://example.com/foo/bar?baz=quux и сервер передает запрос в файл сценария /request_handler.php , $_SERVER['REQUEST_URI'] все равно будет /foo/bar?baz=quux . Я использовал mod_rewrite для сопоставления любого запроса request_handler.php следующим образом:

 RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ /request_handler.php 

Поэтому для правильности, прежде чем использовать $_SERVER['REQUEST_URI'] в пути к файловой системе, вам нужно будет избавиться от строки запроса. Вы можете использовать parse_url для этого:

 $_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); 

Но поскольку это значение приходит непосредственно из строки запроса HTTP без предварительного разрешения пути, оно может по-прежнему содержать символические сегменты пути, такие как.

Тем не менее, обход пути даже не требуется, поскольку запрошенный путь URI уже является абсолютной ссылкой на путь, и запрос на http://example.com/etc/passwd должен привести к включению /etc/passwd .

Таким образом, на самом деле это локальная уязвимость включения файлов .

Теперь, чтобы исправить это, требуется некоторая корневая директория с использованием метода, который вы, chowey, представили, является хорошим улучшением. Но вам действительно нужно было бы префикс его $basedir :

 $path = realpath($basedir . $_SERVER['REQUEST_URI_PATH']); if ($path && strpos($path, $basedir) === 0) { include $path; } 

Это решение дает несколько обещаний:

  • $path – это либо допустимый, разрешенный путь к существующему файлу, либо false ;
  • включение этого файла происходит только в том случае, если $basedir является префиксом пути $path .

Тем не менее, это может по-прежнему разрешать доступ к файлам, которые защищены с помощью какого-либо другого типа контроля доступа, такого как модуль, предоставленный модулем mod_authz_host от Apache .

Это на самом деле не отвечает на вопрос …

Обратите внимание, что вы можете убедиться, что uri запроса указывает на действительный путь к файлу в текущем рабочем каталоге. Вы можете использовать функцию realpath для нормализации пути.

Следующий код мог бы сделать трюк:

 <?php $basedir = getcwd(); $path = $_SERVER['REQUEST_URI']; $path = preg_replace('~\\.html?$~', '.php', $path); $path = realpath($path); if ($path && strpos($path, $basedir) === 0) { include $path; } else { return false; } ?> 

Здесь я использовал strpos чтобы проверить, что $path начинается с $basepath . Поскольку realpath удалит любой ../../.. смешной бизнес, это должно безопасно держать вас в $basepath .

На самом деле не проверяйте $ _SERVER ['REQUEST_URI'] перед проверкой базового пути.

И не делайте фильтр, который удаляет ../ из пути, нападающие могут создать новый способ, если они поймут процессы фильтрации.

У меня был тот же вопрос, и я решил сделать следующее, основываясь на ответе Гумбо :

 $_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $path = realpath(FOLDER_ROOT . $_SERVER['REQUEST_URI_PATH']); $directory_white_list_array = array('/safe_folder1', '/safe_folder1/safe_folder2'); if ($path && strpos($path, FOLDER_ROOT) === 0 && (in_array(dirname($path), $directory_white_list_array) && ('php' == pathinfo($path, PATHINFO_EXTENSION)))) { include $path; }else{ require_once FOLDER_ROOT."/miscellaneous_functions/navigation_error.php"; navigation_error('1'); } 

Сводка: добавлено ограничение каталога и ограничение расширения .php.