PHP包含基于REQUEST_URI

时间:2013-04-20 20:41:30

标签: php security

使用$_SERVER['REQUEST_URI']包含文件是否涉及任何安全风险?你能不能以某种方式通过../../..通过请求uri?

我在想的是这样的:

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

这应该替换“.php”路径的“.htm”或“.html”URI并渲染它们。但我担心这里的安全。

4 个答案:

答案 0 :(得分:3)

$_SERVER['REQUEST_URI']包含HTTP request line中显示的请求的URI路径和查询字符串。因此,当请求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

所以这实际上是local file inclusion vulnerability

现在要解决这个问题,要求使用你所提出的method的某个根目录是一个很好的改进。但实际上你需要用$basedir

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

这个解决方案提供了几个承诺:

  • $path是现有文件的有效解析路径,或false;
  • 仅当$basedir$path的前缀路径时才会包含该文件。

但是,这可能仍允许访问使用其他类型的access control like the one provided by Apache’s mod_authz_host module保护的文件。

答案 1 :(得分:0)

这实际上并没有回答这个问题......

请注意,您可以确保请求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目录中。

答案 2 :(得分:0)

在检查基路径之前,确实不信任$ _SERVER ['REQUEST_URI']。

并且不要制作一个过滤器,从路径中移除../攻击者如果能够理解过滤器过程,就可以采用新的方式进行注入。

答案 3 :(得分:0)

我有同样的问题,并选择以 Gumbo的答案为基础做以下事情:

$_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扩展名限制。