Question

I have a constant beginning of a string, and a variable ending, how can I secure the string so that is doesn't create a step-back (or step-up) in case the string I inject contains

../

Here is a short sample code:

$dir = 'my/base/path/';
$file = $dir . $userSelectedFilename;
unlink($file);

If $userSelectedFilename would be '../../myFileName' I assume that would cause my script to actually try to unlink something two directory levels up my/myFilename which is clearly not something I want to allow, I want to keep it under the basepath my/base/path/ under all circumstances.

Was it helpful?

Solution

I suggest the the following, and only the following method:

<?
$dir = 'my/base/path/';
$file = $dir . $userSelectedFilename;
if(strpos(realpath($file),realpath($dir)) === 0) && is_file($file)) { // beware of the three ===
  unlink($file);
}

Why?

It is safe to rely on realpath to find out the real location of a file which eliminates directory traversal / multibyte double-dots etc.

After that we check whether the beginning of the reapath of the file is really the beginning of our expacted directory (strpos).

After that we also check whether the file is really a file and not some symlink pointing elswhere or something like that.

I have seen character eliminating solutions been broken by multibyte strings and similar attacks.

This method so far far withstands all of these.

OTHER TIPS

You could filter out those characters by doing something like:

$file = preg_match("/\.\.\//", "", $file)

which will remove occurrences of the string ../

And just a side note, you should probably find a different way of allowing users to select files to delete rather than allowing them to input the path as a string, maybe by showing them a directory listing of files they can delete or something like that.

You can do this "my/base/path/../../dir/", if you want "real" path use this :

 echo realpath($dir."../../dir/"); // my/dir

http://php.net/manual/en/function.realpath.php

Using regex to validate the string for ../ or /../ and not accepting the string if the regex returns true:

function validatePath($path) {
    if(preg_match('#\/\.\.\/#',$path))
        return False;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top