阻止/ ..用户输入

时间:2012-02-24 22:13:31

标签: php linux unix validation

我在一个文件夹中有一个php脚本(我把它称为根文件夹)。该脚本基本上可以列出此根文件夹的子文件夹中的所有文件。用户可以使用GET参数指定应显示哪个子文件夹。

script.php?foo

会显示

的内容
<root folder>/foo/

和     script.php的?的.bar 会显示

的内容
<root folder>/.bar/

但是,用户也可以“作弊”并使用/..之类的命令来显示他们无法看到的文件夹的内容。

例如

script.php?/../..

用户可能会在文件夹层次结构中变得非常高。

你是否知道如何防止用户做这样的“作弊”。

为简单起见,我们假设GET参数存储在$searchStatement中。

4 个答案:

答案 0 :(得分:5)

您可以使用realpath来解析绝对路径的相对路径,然后检查该路径是否以“root”文件夹的路径开头:

$absolutePath = realpath(__DIR__ . '/' . trim($searchStatement, '/'));

if (strpos($absolutePath, __DIR__ .'/') !== 0) {
    die('Access denied.');
}

答案 1 :(得分:2)

您应该在使用之前验证输入。

例如,您可能希望仅允许字符a-z/允许子目录。可能你也想允许.。如果你使这个子集变小,那么很容易通过允许的字符来验证是否允许输入。

正如您所注意到的,当您允许.时,您遇到的问题是可以创建相对路径,如/../../,可用于目录遍历攻击

要验证字符串是否仅包含特定范围的字符,可以使用正则表达式或过滤器函数对其进行验证。如果您的网站不需要允许任何相对路径部分,您可以查看它们是否存在于验证输入的路径中:

$valid = !array_intersect(array('', '.', '..'), explode('/', $path));

如果路径中有FALSE///./部分,则有效期为/../

如果您需要允许相对路径,则建议使用realpath,以便首先根据您的目录结构查询输入。我只会把它作为最后的手段,因为它相对昂贵,但是知道它很好。

但是你可以使用一些简单的函数解析你自己的字符串,如下所示:

/**
 * resolve path to itself
 *
 * @param string $path
 * @return string resolved path
 */
function resolvePath($path)
{
    $path = trim($path, '/');
    $segmentsIn = explode('/', $path);
    $segmentsOut = array();

    foreach ($segmentsIn as $in)
    {
        switch ($in)
        {
            case '':
                $segmentsOut = array();
                break;
            case '.':
                break;
            case '..';
                array_pop($segmentsOut);
                break;
            default:
                $segmentsOut[] = $in;
        }
    }
    return implode('/', $segmentsOut);
}

用法:

$tests = array(
    'hello',
    'world/.',
    '../minka',
    '../../42',
    '../.bar',
    '../hello/path/./to/../../world',
);

foreach($tests as $path)
{
    printf("%s -> %s\n", $path, resolvePath($path));
}

输出:

hello -> hello
world/. -> world
../minka -> minka
../../42 -> 42
../.bar -> .bar
../hello/path/./to/../../world -> hello/world

我建议您先使用自己的数据验证输入,然后再触摸文件系统,即使是通过realpath

答案 2 :(得分:1)

查看chroot功能:

  

bool chroot ( string $directory )

     

将当前进程的根目录更改为directory,并将当前工作目录更改为“/”。

对该方法的调用会阻止进一步访问当前目录之外的文件。

但请注意,这需要root权限。

答案 3 :(得分:1)

您是否尝试过使用realpath的内容,它应解决路径中的所有/..。通过测试针对当前路径的realpath参数,例如:

substr($ realpath,0,strlen('/ basepath / cant / go / above'))==='/ basepath / cant / go / above'

您确保所有/..都没有从您想要的地方逃脱。