【问题标题】:Is this safe? (PHP download script)这安全吗? (PHP下载脚本)
【发布时间】:2011-02-09 17:31:38
【问题描述】:

我有一个关于这样做有多安全的问题。我已经编写了一个 php 强制下载脚本,实际提供文件的部分应该看起来很熟悉:

header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header('Content-Length: ' . filesize("user_files/".$temp_actual));
header('Content-Disposition: attachment; filename="'.$filename."\"");
readfile("user_files/".$temp_actual);

$filename 是他们看到的文件名,$temp_actual 是我服务器上的真实文件名。显然,上面有大量代码可以防止坏事发生,但基本上,用户应该能够下载他们上传的任何内容。如果他们上传 .php 文件,我真的不希望它在服务器上运行,我希望它通过强制下载传递给他们(他们确实需要能够上传 any 文件类型) .

它按预期工作,所有文件扩展名都被强制下载,但我只是想绝对确定它们不能在我的服务器上运行任何 php 或 html 文件。

其他信息

user_files 位于网站根目录中,但 .htaccess "deny from all" user_files 目录中的每个文件都附加了 .file 而不是原始扩展名,当用户下载他们的文件时,原始扩展名被替换(可能有点过头了)。

【问题讨论】:

  • 您的问题是关于您所说的所有前面的代码“在此之上的代码山以防止坏事”
  • 不要使用application/force-download;请改用 application/octet-stream
  • 那么这些变量是从哪里来的???你了解什么是输入验证吗?
  • 大声笑@Rook,如果我发布了您将阅读一个小时的整个代码...请阅读下面的“aaz”cmets - 也许您可以提供帮助。我只想知道用户不能告诉我的服务器显示 php 文件而不是下载它。我根本不希望由 php 解析的文件。就像我说的,现在效果很好,但可能有一个我不知道的技巧。
  • @Grant 很酷,你没有给任何人足够的信息来告诉你这是否安全。我只是假设它 100% 安全。祝你有美好的一天。

标签: php security download


【解决方案1】:

user_files 文件夹在您的网站根目录中吗?如果是这样,他们可以上传一个 php 文件并导航到 http://mysite.com/user_files/somefile.php 并运行代码。当然,他们需要知道文件的临时名称,但如果您还没有,您应该确保您的 Web 服务器设置为不允许从该文件夹提供页面(或将其移到文档根目录之外) .

【讨论】:

  • 嘿,它在网站根目录中,但是该文件夹中有一个 .htaccess 文件,其中包含拒绝所有内容:) 谢谢
  • 同样适用于 javascript 和可以欺骗 IE6 将其解释为 javascript 的文件(这意味着几乎任何文件类型)。
【解决方案2】:

清理文件名。有人会尝试上传.htaccess 来替换你的。

即使您将扩展名替换为.file,也会有人尝试上传.htaccess\0.txt,由于a bug,这将起作用。

有人会尝试.\301\250taccess(可能解码为h 的无效UTF-8 序列)。

另外,有人会尝试下载../../../../../etc/shadow

如果您使用的是 Windows,有人会尝试使用 .HTACCESS..\..\..\..\..\windows\system32\conf\sam

"user_file/".$temp_actual 部分在这里很重要:它可以防止触发URL-like filenames。或许可以对此发表评论,这样它就不会被重构掉。

为了完全确定,如果方便的话,请将文件名编码为安全字符。例如。 strtr(base64_encode($filename), '/', '_').

【讨论】:

  • 您好,谢谢您的帮助。我真正想了解的是 - 如果我通过上述方法向他们提供 php 文件,他们是否可以将浏览器设置为从我的主机运行它而不是下载它会显示在窗口中吗?
  • 有了这个bug,他们可以尝试用Allow from all上传.htaccess\0.txt,然后上传evil.php\0.txt,最后通过直接URL访问evil.php。我不确定它是否会起作用,但如果您好奇,可以尝试一下。
  • 嘿,我已经解决了所有的错误,我基本上预先替换了原始文件名中除了 a-zA-Z 之外的所有内容,然后将它们的文件名重命名为 12345.file(存储在 user_files 上filesystem) ,将清理后的文件名和扩展名存储在数据库中。当需要再次获取它时,我从 user_files 中获取 12345.file,更改其名称(在标题,而不是文件系统)附加原始扩展名并将下载框发送给他们...... user_fies 有 .htaccess 拒绝所有和CHMOD 700... 用户可以强制服务器处理应该下载的 php 脚本吗?再次感谢:)
  • 啊,我明白了!在那种情况下 - 可能不会。
  • @aaz 是的,我真的很惊讶 Zend 修补了空字节平衡攻击。十多年来,黑客一直在使用该途径攻击 PHP。
【解决方案3】:

好的,所以答案是:

这样做似乎很安全。对于你们所说的关于输入过滤等的所有内容。让我给你一个简短的介绍:

听着,伙计们,显然有更多的检查,所以请不要回复用户可以上传 xx.xx 并覆盖你的 xx 或从 /../../../../ 下载 xx,尽管我非常感谢你帮助我应该重新处理一下这个问题。假设上传和下载是密封的。

示例文件名 evil.php

  • 上传脚本获取用户文件 剥离任何不是的东西: a-zA-Z0-9,!-_

  • 然后删除扩展名,将其和真实名称存储在数据库中#(和新文件名)

  • 文件被重命名,比如 12345.file 并存储在 user_files 中

  • user_files 的 CHMOD 为 700,并且 .htaccess 拒绝读取所有文件

  • 当用户想要获取他们的文件时,脚本访问数据库并获取真实文件名、旧文件名和扩展名,它告诉用户浏览器文件名是 oldfilename.extension (evil.extension)。 php) 但是它仍然作为 12345.file 在文件系统上。然后它为下载设置标题并使用 readfile() 将内容读取到浏览器。

为了检查用户无法让我的服务器解析 php,我注释掉了打开保存文件下载框的标题并只使用了 readfile()。结果是 php 被转储到页面,但 NOT PARSED。用 eval() 进一步测试表明它也没有被解析。哪个最有帮助。 =)

(仔细阅读后,上面的标题应该从 application/force-download 更改为 application/octet-stream(正确的 mime 类型)。

感谢所有回复您所有帮助的人 - 我希望这可以为将来偶然发现此问题的任何人澄清问题!

和平!

【讨论】:

    【解决方案4】:

    您是否考虑过在上传时更改(附加)文件扩展名? 说myFile.php变成myFile.php.txt

    您仍然可以使用 substr() 之类的东西将文件(用于下载目的)显示为 .php,但使用 .txt 扩展名会使它们无法在服务器上实际运行 - 无论目录层次结构/位置如何。

    【讨论】:

    • @aaz - 不错的收获,我不知道。不过我的目标是一样的。保持简单,让它变得无用......即使有这个错误,在上传时也不会检查“htaccess”(并且使用 RegEx 禁止该名称)会阻止问题发生?
    • 当然,提交者可能已经这样做了。但很难完全正确。而且你不能过分热心,因为有人可能会合法地上传nightaccess.doc 或其他东西。但是你必须保护 PHP 虚拟层、Apache 虚拟层和 OS 文件系统。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 2012-03-20
    相关资源
    最近更新 更多