views:

52

answers:

4

I have a PHP script that tests is the user is logged in, for every page he accesses in a certain subdirectory. If he's logged in, he gets the page, otherwise he gets redirected to a login page. Instead of including this into every file (not possible since some are binary), I set up .htaccess like this

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !^$
RewriteRule (.*) /check.php?filename=special/$1

And the contents of check.php are

if (!isset($_SESSION['username']))
{
    header("location: /login.html");
    die();
}
$filename = $_GET['filename'];
include($filename);

The problem is that check.php is vulnerable to local file inclusion because I can pass ../ in filename to move to the parent directory and even leave /var/www. How can I restrict it to only reading from the special directory, or is there any way I can un-rewrite if the PHP check passes to allow Apache to read the target file instead of the PHP script reading the file?

Edit I also have subdirectories in the special directory. check.php is in the parent directory of the special directory.

A: 
$filename = basename($_GET['filename']);

will leave only filename off any given string

Col. Shrapnel
Sorry, I forgot to add that I also have subdirectories in the directory, so I can't drop the whole path.
Dmi
A: 

First, drop the '/special' part from your mod_rewrite rule, there is no need for it, you just want a file name.

Then try this:

$your_dir = '/full/path/to/special';
$filename = basename($_GET['filename']);
if (file_exists($your_dir . '/' . $filename)) {
    include($filename);
}

basename() will cut off any path from $filename.

Anti Veeranna
A: 

This worked:

$filename = realpath($_GET['filename']);
if (strpos($filename, '/full/path/to/special') !== 0)
{
die();
}

If the real path to the filename doesn't start with that string, it aborts.

Dmi
A: 

Wouldn't it just be simpler to set an auto-prepend for the dir tree?

symcbean
If I prepend "subdir/" and someone enters "../file", they get "/file" instead of "subdir/file". The function realpath solves all of this to show exactly what path it's going to, and if it doesn't start with "subdir/", I know it's out of the directory.
Dmi