Php 防止/。。用户输入
我在一个文件夹中有一个php脚本(我称之为根文件夹)。脚本基本上可以列出此根文件夹子文件夹中的所有文件。用户可以使用GET参数指定应显示的子文件夹Php 防止/。。用户输入,php,linux,unix,validation,Php,Linux,Unix,Validation,我在一个文件夹中有一个php脚本(我称之为根文件夹)。脚本基本上可以列出此根文件夹子文件夹中的所有文件。用户可以使用GET参数指定应显示的子文件夹 script.php?foo 将显示 <root folder>/foo/ <root folder>/.bar/ 用户可能在文件夹层次结构中处于非常高的位置 你有没有办法防止用户这样做“作弊”呢 为了简单起见,假设GET参数存储在$searchStatement中。请查看函数: boolchroot(字符串$direc
script.php?foo
将显示
<root folder>/foo/
<root folder>/.bar/
用户可能在文件夹层次结构中处于非常高的位置
你有没有办法防止用户这样做“作弊”呢
为了简单起见,假设GET参数存储在$searchStatement
中。请查看函数:
boolchroot(字符串$directory)
将当前进程的根目录更改为目录,将当前工作目录更改为“/”
对该方法的调用将阻止进一步访问当前目录之外的文件
但是请注意,这需要根权限。您可以使用
realpath
将相对路径解析为绝对路径,然后检查该路径是否以“根”文件夹的路径开始:
$absolutePath = realpath(__DIR__ . '/' . trim($searchStatement, '/'));
if (strpos($absolutePath, __DIR__ .'/') !== 0) {
die('Access denied.');
}
如果您尝试了某项功能,它将解析路径中的所有
/..
。通过针对当前路径测试参数的realpath
,如下所示:
substr($realpath,0,strlen('/basepath/cant/go/over'))==='/basepath/cant/go/over'
确保任何
/..
都没有从您想要的地方逃逸。您只需在使用输入之前验证输入
例如,您可能希望只允许字符a-z
和/
允许子目录。可能您也希望允许
。如果将此子集设置得很小,则很容易验证输入是否已被允许的字符所允许
正如您所注意到的,在您允许
的那一刻,您有一个问题,即可以创建相对路径,如/../../
,它可以用于目录遍历攻击
要验证字符串是否只包含特定范围的字符,可以使用正则表达式或筛选器函数进行验证。如果您的网站不需要允许任何相对路径部分,您可以查看它们是否存在于路径中,以验证输入:
$valid = !array_intersect(array('', '.', '..'), explode('/', $path));
如果路径中存在任何/
或/././
或//../
部分,则有效值将为FALSE
如果您需要允许相对路径,已经有人建议您,因此首先根据目录结构查询输入。我只会把它作为最后的手段,因为它相对昂贵,但知道它很好
但是,您也可以使用以下简单函数解析自己的字符串:
/**
* 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
也行!但是,我没有root特权:(基本上是我的想法,但更好更快一点;)+1听起来像是一个非常好的解决方案!我明天就试试,然后接受你的回答!代码看起来不错。但您对realpath“相对昂贵”是什么意思?非常感谢。你是说像运行时一样昂贵吗?因为我的脚本不会同时有很多用户(它位于页面的一个私有区域),所以我并不介意。首先,从开发人员的角度了解这一点很好。从磁盘I/O的意义上讲,它是昂贵的。它是一种文件系统功能,因此如果使用它,您已经接触到了文件系统。您可能希望防止这种情况发生,因为您仍在验证输入。resolvePath
函数并不严格,但应该给出一个示例。但是我认为您应该直接阻止这种类型的输入,只是使恶意请求无效。
hello -> hello
world/. -> world
../minka -> minka
../../42 -> 42
../.bar -> .bar
../hello/path/./to/../../world -> hello/world