当第三方外部引用作为文件名给出时,fread()、file() 和 file_get_contents() 函数对服务器来说是否安全?

Are fread(), file() and file_get_contents() functions secure to the server when third-party external references are given as filename?

简介

我问这个问题是因为我关于这个主题的所有发现的答案都集中在变量 $filename 值的风险上(我已经理解并知道安全使用的字符串处理要求)。我还发现了一个关于 的问题,但它以 OP 要求他的代码的 cURL 版本而告终。

我想知道 fread()file()file_get_contents() 函数在通过外部流与第三方网站交互时是否安全 $filename 参考(即外部链接如 https://www.example.com 而不是内部文件路径如 includes/my-file.php)。

例子

以下简单应用程序对服务器的安全问题是什么,它打开给定的站点内容,将其所有源代码“foobar”替换为“barbaz”并将其打印给用户?

// User given URL.
$user_url = $_POST['url'] ?? null;

// Conditional content.
if (is_string($user_url) && preg_match('/^https?:\/\/.+$/', $user_url)) {
    // Print content with replacements.
    print_r(str_replace("foobar", "barbaz", file_get_contents($user_url)));
} else {
    // Warning.
    if (is_string($user_url)) echo '<p>' . "You inserted an invalid URL :(" . '</p>';
    // Form.
    echo '<form method="post" action="">' .
        '<label for="url-field">Your URL:</label>' .
        '<input id="url-field" name="url" type="text">' .
        '<button type="submit">Do it!</button>';
        '</form>';
}

同样,我知道 preg_match('/^https?:\/\/.+$/', $user_url) 是一个过于简单的过滤器,给定字符串的其他特征也应该被分析(例如长度)。

更多详情

我的目标是了解 PHP 用于获取 file_get_contents()file()fread() 内容的程序是否确实存在所咨询的任何已知漏洞第三方站点可以利用,这对应用程序服务器构成风险。

我不关心返回的字符串,因为带有恶意 JS 的源代码不会是服务器端问题,而且我不会在我的代码中写 eval(file_get_contents($url)) 之类的东西。

此外,确认 none 的客户端 HTTP 请求数据(到我的应用程序)或 cookie 将被发送到第三方网站(除非通过自定义上下文明确完成)是否正确?

我对这些函数的困惑部分是由于处理内部服务器文件路径和外部引用之间的方法差异。第一个让他们打开文件并读取其中的行,第二个需要互联网协议(我还是有点缺乏经验)来获取函数的返回内容。

大多数(也许是全部)PHP file-based 操作是通过 streams 完成的,每个流包装器(文件、http、ftp 等)都有它们的自己的代码和逻辑,这意味着每个 可能 也有潜在的安全漏洞。

默认的流包装器及其相应的处理程序也可以在 source, and there's a great deep dive for implementors here 中找到。

您可以手动 register your own stream wrappers, too. In fact, you can also unregister existing wrappers,可能是核心代码(我没试过),因此您或其他人理论上也可以注入易受攻击的代码。

据我所知,目前维护的 PHP 版本中没有与这些包装器相关的公开宣布的未修补漏洞。这并不是说在past there weren't中,也不是说我知道任何未公开的。

关于你的第二个问题,,当网络浏览器访问 PHP 页面时,该页面使用 file_get_contents 反对 HTTP/HTTP 流,浏览器的初始请求(headers 等)中的任何内容都不会添加到流的请求中。该部分称为每个包装器的“stream context". The default values for an unspecified context can be manually inspected in the source。查找类似 context && (tmpzval = php_stream_context_get_option 的代码,然后找到相应的 else