I want to make sure a file path set via query string does not go outside of the desired subdirectory. Right now, I am checking that:
- The path does not start with "
/
", to prevent the user from giving an absolute path. - The path does not contain "
..
", to prevent the user from giving a path that is outside of the desired subdirectory. - The path does not contain "
:
", to prevent the use of a url (i.e. "http://
", "ftp://
", etc.). Should I ever run this script on a Windows server (not likely), this will also prevent absolute paths beginning with a drive specifier (i.e. "C:\
"). Note: I'm aware that a colon is a valid character in a Unix filenames, but I will never be using it in a filename. - The path does not start with "
\
". Just in case I change my mind about running on a Windows server, this prevents Windows network paths from being specified (i.e. "\\someserver\someshare
"). Again, I'm aware that a backslash is a valid Unix filename character, but I also won't be using it in any filenames.
Are these checks sufficient?
Background
I have a PHP script that takes (via query string) the path to a sample source file to be shown to a user. So I might give them a link like "view_sample.php?path=accounting_app/report_view.php
" or "view_sample.php?path=ajax_demo/get_info.js
".
The script looks basically like this:
$path = $_GET['path'];
if(path_is_valid($path) && is_file("sample/$path"))
{
header('Content-Type: text/plain');
readfile("sample/$path");
}
My concern is that a malicious user would see the url and try to do something like "view_sample.php?path=../../database/connection_info.php
" and gain access to a file which is not in the "sample" directory.
Are the four checks I defined above (which would be implemented in the path_is_valid()
function) sufficient to lock out a malicious user? (Also, I think checks 1, 3, and 4 are basically irrelevant since I am prepending a relative path, but if I didn't do this would the checks be sufficient?)
Call
$path = realpath("sample/$path");
Then check that the resulting path starts with the directory you're expecting.
<?php
// Current path information
$path = $_GET['path'];
$vroot = "sample";
// Validate that the $path is a subfolder of $vroot
$vroot = realpath($vroot);
if(substr(realpath($path), 0, strlen($vroot)) != $vroot or !is_dir($path)) {lid!
exit("Invalid path");
} else {
echo "Ah, everything is alright!";
}
?>
The use of realpath should not change the path, so I use it in the following way:
function checkPath($pathToCheck) {
global $basepath;
$fullpath = $basepath.'/'.$pathToCheck;
if ($fullpath==realpath($fullpath) && is_dir($fullpath)) {
return $fullpath;
} else {
error_die('path not allowed: '.htmlentities($pathToCheck));
}
}
来源:https://stackoverflow.com/questions/456546/how-do-i-make-sure-a-file-path-is-within-a-given-subdirectory