Существуют ли какие-либо риски безопасности при использовании $_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.