$_SERVER['REQUEST_URI']
使用包含文件是否存在任何安全风险?你能../../..
以某种方式通过请求uri吗?
我在想的是这样的:
<?php
$path = $_SERVER['REQUEST_URI'];
$path = preg_replace('~\\.html?$~', '.php', $path);
include $path;
?>
这应该用“.htm”或“.html” URI 替换“.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
。但是,这可能仍然允许访问使用某种其他类型的访问控制保护的文件,例如 Apache 的 mod_authz_host 模块提供的访问控制。
我有同样的问题,并根据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扩展名限制。
在检查基本路径之前,确实不要相信 $_SERVER['REQUEST_URI'] 。
并且不要制作从路径中删除 ../ 的过滤器,如果攻击者了解过滤器过程,他们可以制作一种新的注入方式。
这实际上并没有回答这个问题......
请注意,您可以确保请求 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
目录中。