如何确保文件路径位于给定的子目录内?

发布于 2024-07-12 05:54:06 字数 1257 浏览 6 评论 0原文

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

  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 基本上是无关紧要的,因为我预先考虑了相对路径,但如果我不这样做,检查就足够了吗?)

I want to make sure a file path set via query string does not go outside of the desired subdirectory. Right now, I am checking that:

  1. The path does not start with "/", to prevent the user from giving an absolute path.
  2. The path does not contain "..", to prevent the user from giving a path that is outside of the desired subdirectory.
  3. The path does not contain ":", to prevent the use of a url (i.e. "http://", "ftp://", etc.). Should I ever run this script on a Windows server (not likely), this will also prevent absolute paths beginning with a drive specifier (i.e. "C:\"). Note: I'm aware that a colon is a valid character in a Unix filenames, but I will never be using it in a filename.
  4. The path does not start with "\". Just in case I change my mind about running on a Windows server, this prevents Windows network paths from being specified (i.e. "\\someserver\someshare"). Again, I'm aware that a backslash is a valid Unix filename character, but I also won't be using it in any filenames.

Are these checks sufficient?

Background

I have a PHP script that takes (via query string) the path to a sample source file to be shown to a user. So I might give them a link like "view_sample.php?path=accounting_app/report_view.php" or "view_sample.php?path=ajax_demo/get_info.js".

The script looks basically like this:

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

My concern is that a malicious user would see the url and try to do something like "view_sample.php?path=../../database/connection_info.php" and gain access to a file which is not in the "sample" directory.

Are the four checks I defined above (which would be implemented in the path_is_valid() function) sufficient to lock out a malicious user? (Also, I think checks 1, 3, and 4 are basically irrelevant since I am prepending a relative path, but if I didn't do this would the checks be sufficient?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

┊风居住的梦幻卍 2024-07-19 05:54:07
<?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!";
    }
?>
<?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!";
    }
?>
巷雨优美回忆 2024-07-19 05:54:07

使用 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));
    }
}

The use of realpath should not change the path, so I use it in the following way:

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));
    }
}
∞琼窗梦回ˉ 2024-07-19 05:54:06

调用

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

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

Call

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

Then check that the resulting path starts with the directory you're expecting.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文