Php 我的代码有什么安全问题?

Php 我的代码有什么安全问题?,php,security,Php,Security,几年前,我发布了一个问题,在PHP中,允许用户在URI中传递要下载的文件的相对路径,同时防止目录遍历 我收到一些评论,告诉我代码不安全,还有一些反对票(最近的是今天)。代码如下: $path = $_GET['path']; if (strpos($path, '../') !== false || strpos($path, "..\\") !== false || strpos($path, '/..') !== false || strpos($path, '\..

几年前,我发布了一个问题,在PHP中,允许用户在URI中传递要下载的文件的相对路径,同时防止目录遍历

我收到一些评论,告诉我代码不安全,还有一些反对票(最近的是今天)。代码如下:

$path = $_GET['path'];
if (strpos($path, '../') !== false ||
    strpos($path, "..\\") !== false ||
    strpos($path, '/..') !== false ||
    strpos($path, '\..') !== false)
{
    // Strange things happening.
}
else
{
    // The request is probably safe.
    if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . $path))
    {
        // Send the file.
    }
    else
    {
        // Handle the case where the file doesn't exist.
    }
}
我一次又一次地检查代码,并对其进行测试,但仍然无法理解它带来的安全问题

我在评论中得到的唯一提示是,
。/
可以替换为
%2e%2e%2f
。这不是问题,因为PHP会自动将其转换为
。/


这段代码有什么问题?允许目录遍历或以某种方式破坏某些内容的输入值是多少?

还有许多其他可能的情况,例如:

.htaccess
some-secret-file-with-a-password-in-it.php

换句话说,目录或子目录中的任何内容都可以访问,包括
.htaccess
文件和源代码。如果该目录或其子目录中的任何内容不可下载,则这是一个安全漏洞。

黑名单是一个坏习惯。最好使用白名单(允许使用文字字符串或字符)

或者:

switch($path) {
    case 'page1':
    case 'page2':
        // ...
        break;
    default:
        $path = 'page1';
        break;
}

include $path;

我想不出哪种情况会失败

然而,我不知道PHP的
文件是如何在内部实现的,也不知道它是否有一些目前未知的怪癖。就像


因此,为了安全起见,我宁愿检查已经解析的路径,而不是盲目地相信PHP,而且——可能更重要的是——我的假设是,上述四个序列是唯一可以导致路径位于指定基目录之上的序列。这就是为什么我更愿意这样做。

我刚刚运行了您的代码,在本例中找不到任何解决方法

它可能被否决,因为它利用了其他/旧的技术堆栈,采用了类似的方法,将某些字符组合列入黑名单

正如您所提到的,当前版本的PHP会自动对输入进行URL解码,但在使用诸如双URL编码(dot=
%252e
)、16位Unicode编码(dot=
%u002e
)、过长的UTF-8Unicode编码(dot=
%c0%2e
)或插入空字节(
%00
)等技术时存在缺陷可以欺骗过滤器,并允许服务器端代码在过滤器对路径竖起大拇指后将其解释为未编码版本


这就是它敲响警钟的原因。尽管您的方法在这里似乎有效,但通常情况可能并非如此。技术总是在不断变化,最好是谨慎行事,尽可能使用不受字符集解释影响的技术,例如使用已知良好字符的白名单,这些字符可能总是良好的,或者使用文件系统功能(链接答案中提到)验证实际路径是否为您所期望的路径。

/etc/passwd
仍然有效accepted@SLaks:URI将给出类似于
/home/demo site/etc/passwd
的结果,所以不,这不是问题。问得好。虽然它真的很痒,但我还不能真正找到一个错误,而且它真的很烦人,
/etc/passwd
的建议在这里得到了所有的赞成票。。。虽然我错了。安全性很好,但是因为..把FUD扔来扔去。。因为这不是很酷。我仍然不会对这段代码感到满意(为什么不进行类型检查?将其限制在某个白名单上,等等),但事实上,所有这些下跪也是不好的,这是如何得到-2的?这是一个严肃而明确的问题,通过+5-ed的评论,很多路人都会出错,所以对一些人来说这一点都不无关紧要……你的代码应该从(从原始问题的路径开始)
$path='/whater/path/'+$\u get['path'],然后可以删除遍历并确保它仍在正确的文件夹中。(虽然“%2e%2e%2f”可能仍然有问题),但这三条路径都会指向基本目录中的文件。考虑到我所引用的问题/答案的上下文,我不认为这是一个安全问题。我没有看到任何问题(或链接的问题和答案)表明目录中的所有文件都可以下载。如果我错过了什么,请告诉我。然而,这是一个潜在的安全漏洞,所以这是对这个问题的有效回答。@Nanne我已经修改了我的答案,实际上它说的差不多。
switch($path) {
    case 'page1':
    case 'page2':
        // ...
        break;
    default:
        $path = 'page1';
        break;
}

include $path;