PHP目录遍历问题

3

你好,我们有一些使用file_get_contents()函数的php代码,我了解到这可能会受到目录遍历攻击。以下是给定的代码:

$mydata=$_GET['thefile'];
$data = file_get_contents ('/var/html'.$file);
echo $data

我该如何进行简单的输入过滤,以防止有人通过操纵我的输入来进行目录遍历?

/MR


2
$file 是在哪里设置的? - KyleWpppd
我认为你的关注点是防止访问相对路径(例如“/path/to/somedir/../../../etc/passwd”),是吗? - AJ.
正确,这里的主要问题正如您所指出的那样,是相对路径的访问。 - MRD
2个回答

3
你想要使用basename函数:
$mydata = basename(realpath($_GET['thefile']));

以下是需要翻译的内容:

在您的示例代码上进行了微小修改并附加:

$file=$_GET['thefile']; 
$mypath='/var/www/';
$location= basename(realpath($mypath.$file));
$data = file_get_contents($location);
echo $data;

请注意...虽然这里进行了某些级别的错误检查,但没有进行错误处理。我会把这留给你来处理。


@zerkms - 那我就漏了什么...那正是basename所做的。我刚刚测试过了。 - John Green
@John Green - PageSpike:如果 OP 不需要指定像 asd/file.html 这样的嵌套目录,那么这个方法可以行得通。 - zerkms
@zerkms - 太好了...我有点困惑。 : ) - John Green
@John Green - PageSpike:是的,我不够注意,所以我在一瞬间添加和删除了两次我的评论;-) - zerkms
那么basename()如何防止访问相对路径?我觉得我在这里漏掉了什么 :-) 如果在变量$ _GET中使用../作为输入,我仍然可以访问相对路径,不是吗? - MRD
显示剩余6条评论

1

如果$_GET['thefile']不使用像"images/fileX.jpg"这样的文件夹,您可以使用basename()

$filename = basename($_GET['thefile']);
readfile('/var/html/'.$filename);

当把'../../passwords.txt'作为$_GET['thefile']给出时,它将被basename转换为'passwords.txt'。
在basename内添加realpath()不会增加任何安全性。

如果您的脚本确实需要支持子目录,则使用 realpath()来确定它是否在'/var/html'目录内。

$baseDir = realpath('/var/html/'); // (mayby /var/html is a symlink)
$baseDirLength = strlen($baseDir);
$filepath = realpath('/var/html/'.$_GET['thefile']);
if (substr($filepath, 0, $baseDirLength) == $baseDir) {
   // Even when all the '../' in the thefile are resolved 
   // the path is within the $baseDir
} else {
  // invalid $_GET['thefile']
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接