Reputation:
I am in a situation where I need to allow a user to download a file dynamically determined from the URL. Before the download begins, I need to do some authentication, so the download has to run through a script first. All files would be stored outside of the web root to prevent manual downloading.
For example, any of the following could be download links:
Basically, the folder depth can vary.
To prevent a directory traversal, like say: http://example.com/downloads/../../../../etc/passwd I need to obviously do some checking on the URI. (Note: I do not have the option of storing this info in a database, the URI must be used)
Would the following regexp be bullet-proof in making sure that a user doesnt enter something fishy:
preg_match('/^\/([-_\w]+\/)*[-_\w]+\.(zip|gif|jpg|png|pdf|ppt|png)$/iD', $path)
What other options of making sure the URI is sane do I have? Possibly using realpath in PHP?
Upvotes: 3
Views: 5859
Reputation: 91
My solution
$filesPath = realpath(".");
$reqPath = realpath($_GET["file"]);
$pat = "%^".preg_quote($filesPath)."%";
if(preg_match($pat,$reqPath)){
echo "File found";
}else{
echo "Access denied"
}
?>
Upvotes: 0
Reputation:
I think the following 3 checks can be an ideal solution
Upvotes: 1
Reputation: 40240
I would recommend using realpath()
to convert the path into an absolute. Then you can compare the result with the path(s) to the allowed directories.
Upvotes: 6
Reputation: 25775
I'm not a PHP developer but I can tell you that using a Regex based protection for such a scenario is like wearing a T-shirt against a hurricane.
This kind of problem is known as a Canonicalization vulnerability in security parlance (whereby your application parses a given filename before the OS has had a chance to convert it to its absolute file path). Attackers will be able to come up with any number of permutations of the filename which would almost certainly fail to be matched by your Regex.
If you must use Regex, then make it as pessimistic as possible (match only valid filenames, reject everthing else). I would suggest that you do some research on Canonicalization methods in PHP.
Upvotes: 3
Reputation: 31903
What characters will your filenames contain? If it's simply [a-zA-Z0-9] single dots dashes and slashes then feel free to strip anything else.
Upvotes: 0