防止 PHP 中的目录遍历,但允许路径
2022-08-30 12:07:09
我有一个基本路径 /whatever/foo/
并且应该相对于它。$_GET['path']
但是,如何在不允许目录遍历的情况下完成此操作(读取目录)?
例如。
/\.\.|\.\./
无法正确筛选。
我有一个基本路径 /whatever/foo/
并且应该相对于它。$_GET['path']
但是,如何在不允许目录遍历的情况下完成此操作(读取目录)?
例如。
/\.\.|\.\./
无法正确筛选。
好吧,一种选择是比较实际路径:
$basepath = '/foo/bar/baz/';
$realBase = realpath($basepath);
$userpath = $basepath . $_GET['path'];
$realUserPath = realpath($userpath);
if ($realUserPath === false || strpos($realUserPath, $realBase) !== 0) {
//Directory Traversal!
} else {
//Good path!
}
基本上,realpath() 会将提供的路径解析为实际的硬物理路径(解析符号链接、、、、等)...因此,如果真实用户路径不以真实基本路径开头,则它正在尝试进行遍历。请注意,的输出将没有任何“虚拟目录”,例如 或 ......///realpath...
ircmaxell的答案并不完全正确。我已经在几个片段中看到了该解决方案,但它有一个与的输出相关的错误。该函数删除了尾随目录分隔符,因此想象两个连续的目录,例如:realpath()realpath()
/foo/bar/baz/
/foo/bar/baz_baz/
与删除最后一个目录分隔符一样,如果等于“..”,则您的方法将返回“良好路径”。/baz_baz“,因为它会像这样realpath()$_GET['path']
strpos("/foo/bar/baz_baz", "/foo/bar/baz")
或:
$basepath = '/foo/bar/baz/';
$realBase = realpath($basepath);
$userpath = $basepath . $_GET['path'];
$realUserPath = realpath($userpath);
if ($realUserPath === false || strcmp($realUserPath, $realBase) !== 0 || strpos($realUserPath, $realBase . DIRECTORY_SEPARATOR) !== 0) {
//Directory Traversal!
} else {
//Good path!
}