PHP Include based on REQUEST_URI

懵懂的女人 提交于 2020-01-05 06:08:51

问题


Is there any security risks involved in using $_SERVER['REQUEST_URI'] to include a file? Can you pass ../../.. through the request uri somehow?

What I'm thinking is something like this:

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

This should substitute ".htm" or ".html" URIs for ".php" paths and render them. But I am concerned about security here.


回答1:


$_SERVER['REQUEST_URI'] contains the requested URI path and query string as it appeared in the HTTP request line. So when http://example.com/foo/bar?baz=quux is requested and the server passes the request to the script file /request_handler.php, $_SERVER['REQUEST_URI'] would still be /foo/bar?baz=quux. I’ve used mod_rewrite to map any request to request_handler.php as follows:

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

So for correctness, before using $_SERVER['REQUEST_URI'] in a file system path, you would need to get rid of the query string. You can use parse_url to do so:

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

But as this value comes directly from the HTTP request line without prior path resolution, it may still contain symbolic path segments like ...

However, path traversal is not even necessary as the requested URI path is already an absolute path reference and requesting http://example.com/etc/passwd should result in the inclusion of /etc/passwd.

So this is actually a local file inclusion vulnerability.

Now to fix this, requiring a certain root directory using the method that you, chowey, have presented is a good improvement. But you would actually need to prefix it with $basedir:

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

This solution provides several promises:

  • $path is either a valid, resolved path to an existing file, or false;
  • inclusion of that file does only happen if $basedir is a prefix path of $path.

However, this may still allow access to files which are protected using some other kind of access control like the one provided by Apache’s mod_authz_host module.




回答2:


This does not actually answer the question...

Note that you can ensure the request uri points to an actual valid filepath in the current working directory. You can use the realpath function to normalize the path.

The following code would do the trick:

<?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;
}
?>

Here I used strpos to verify that the $path starts with $basepath. Since realpath will have removed any ../../.. funny business, this should safely keep you within the $basepath directory.




回答3:


Indeed dont trust the $_SERVER['REQUEST_URI'] before checking the basepath.

And dont make a filter that removes ../ from the path attackers can craft a nieuw way to inject if they understand the filter proces.




回答4:


I had the same question and chose to do the following basing myself on Gumbo's answer :

$_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');
}

Summary: Added directory whitelist and .php extension restriction.



来源:https://stackoverflow.com/questions/16124970/php-include-based-on-request-uri

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!