【问题标题】:How do I make sure a file path is within a given subdirectory?如何确保文件路径在给定的子目录中?
【发布时间】:2010-10-02 04:13:12
【问题描述】:

我想确保通过查询字符串设置的文件路径不会超出所需的子目录。现在,我正在检查:

  1. 路径不以“/”开头,防止用户给出绝对路径。
  2. 路径不包含“..”,以防止用户提供位于所需子目录之外的路径。
  3. 路径不包含“:”,以防止使用url(即“http://”、“ftp://”等)。如果我曾经在 Windows 服务器上运行此脚本(不太可能),这也将阻止以驱动器说明符开头的绝对路径(即“C:\”)。注意:我知道冒号是 Unix 文件名中的有效字符,但我永远不会在文件名中使用它。
  4. 路径不以“\”开头。以防万一我改变主意在 Windows 服务器上运行,这会阻止指定 Windows 网络路径(即“\\someserver\someshare”)。同样,我知道反斜杠是有效的 Unix 文件名字符,但我也不会在任何文件名中使用它。

这些检查是否足够?

背景

我有一个 PHP 脚本,它(通过查询字符串)获取要显示给用户的示例源文件的路径。所以我可能会给他们一个链接,比如“view_sample.php?path=accounting_app/report_view.php”或“view_sample.php?path=ajax_demo/get_info.js”。

脚本基本上是这样的:

$path = $_GET['path'];
if(path_is_valid($path) && is_file("sample/$path"))
{
  header('Content-Type: text/plain');
  readfile("sample/$path");
}

我担心恶意用户会看到该网址并尝试执行“view_sample.php?path=../../database/connection_info.php”之类的操作并获得对“示例”目录中的文件的访问权限。

我上面定义的四项检查(将在path_is_valid() 函数中实现)是否足以锁定恶意用户? (另外,我认为检查 1、3 和 4 基本上是无关紧要的,因为我预先添加了一个相对路径,但如果我不这样做,检查就足够了吗?)

【问题讨论】:

    标签: php security sanitization


    【解决方案1】:

    打电话

    $path = realpath("sample/$path");
    

    然后检查生成的路径是否以您期望的目录开头。

    【讨论】:

    • 不,realpath 没有这样的事情。 realpath() 扩展所有符号链接并解析对输入路径中的 '/./'、'/../' 和额外的 '/' 字符的引用。并返回规范化的绝对​​路径名。 ca.php.net/manual/en/function.realpath.php
    • 这不是需要的吗(可能减去符号链接分辨率)?如果您有规范化形式的路径,您可以轻松找到它真正引用的目录(检查它是否以“/var/www/data/”开头或您的数据在哪里)。
    • 实际上这听起来像它会做我想要的.. 如果用户以某种方式指定了仍然在示例目录中的相对路径,我真的不在乎(即“../sample /.././sample/./.././sample/thefile.php").
    • 不要指望realpath 保护您免受directory traversal attack 的侵害。 @Samuel 是对的。
    • @Flimm,但是当您检查两个路径时​​,您都使用 realpath 。所以不存在安全风险。是的,您的示例中的 $path 可以指向 /etc/passwd,但随后您将其与默认路径(例如 /home/test)进行比较,您可以确定它是无效的。所以 realpath 和 strpos 就足够安全了
    【解决方案2】:
    <?php
        // Current path information
        $path = $_GET['path'];
        $vroot = "sample";
    
        // Validate that the $path is a subfolder of $vroot
        $vroot = realpath($vroot);
        if(substr(realpath($path), 0, strlen($vroot)) != $vroot or !is_dir($path)) {lid!
            exit("Invalid path");
        } else {
           echo "Ah, everything is alright!";
        }
    ?>
    

    【讨论】:

    • 如果$pathsamplefoo/bar.txt(显然不是sample 的后代),这将通过。
    • @Soronbe:实际上并没有,因为$vroot = realpath($vroot); 会删除任何尾部斜杠。
    • $vroot = realpath($vroot). DIRECTORY_SEPARATOR; ?
    【解决方案3】:

    realpath的使用应该不会改变路径,所以我是这样使用的:

    function checkPath($pathToCheck) {
        global $basepath;
        $fullpath = $basepath.'/'.$pathToCheck;
        if ($fullpath==realpath($fullpath) && is_dir($fullpath)) {
            return $fullpath;
        } else {
            error_die('path not allowed: '.htmlentities($pathToCheck));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-05-16
      • 1970-01-01
      • 2017-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-06
      • 2018-05-31
      • 2015-07-30
      相关资源
      最近更新 更多