正则表达式检查路径是否仅下降

Let*_*eto 5 php regex security path filepath

我想测试用户给出的路径是否如下:

my/down/path

在相反的:

this/path/../../go/up

出于安全原因.

我已经做到了这个:

return (bool)preg_match('#^([a-z0-9_-])+(\/[a-z0-9_-])*$#i', $fieldValue);
Run Code Online (Sandbox Code Playgroud)

但是应该允许用户'.'在他的路径中使用(例如:my/./path,这没用,但他可以),我不知道如何考虑它.

我正在寻找一个安全的正则表达式来检查这个.

谢谢

编辑:查看答案后,是的,如果测试检查真实路径(删除'.''..')是否为下行路径,那就没问题了.

Gor*_*don 5

您可以简单地检查用户提供的路径的真实路径是否以允许的路径开头:

function isBelowAllowedPath($allowedPath, $pathToCheck)
{
    return strpos(
        realpath($allowedPath . DIRECTORY_SEPARATOR . $pathToCheck), 
        realpath($allowedPath)
    ) === 0;
}
Run Code Online (Sandbox Code Playgroud)

在键盘上演示

请注意,这也将返回false下面不存在的目录$allowedPath

  • 根据您对“realpath”的确切需求,它可能不适用。`realpath` 要求路径名存在,即您不能使用此检查来创建新路径。此外,`realpath` 将在某些边缘情况下失败,例如 Phar 档案。 (2认同)

Nik*_*kiC 2

您可能不想检查路径是否不包含..,而是想检查如果作为整体求值,则它不会上升。即使它包含 ,但Eg./path/..仍然存在。...

您可以在 Twig 中找到路径深度验证的实现:

$parts = preg_split('#[\\\\/]+#', $name);
$level = 0;
foreach ($parts as $part) {
    if ('..' === $part) {
        --$level;
    } elseif ('.' !== $part) {
        ++$level;
    }

    if ($level < 0) {
        return false;
    }
}

return true;
Run Code Online (Sandbox Code Playgroud)

Twig 不用于realpath验证,因为realpathPhar 档案中的路径存在问题。此外,realpath仅当路径名已存在时才有效。