【问题标题】:Force image download - .php files download强制图像下载 - .php 文件下载
【发布时间】:2016-05-11 17:31:58
【问题描述】:

这是我的下载.php;

session_start();
$file = $_GET['file']; 

    download_file($file); 
function download_file( $fullPath ){

  // Must be fresh start
  if( headers_sent() )
    die('Headers Sent');

  // Required for some browsers
  if(ini_get('zlib.output_compression'))
    ini_set('zlib.output_compression', 'Off');

  // File Exists?
  if( file_exists($fullPath) ){

    // Parse Info / Get Extension
    $fsize = filesize($fullPath);
    $path_parts = pathinfo($fullPath);
    $ext = strtolower($path_parts["extension"]);

    // Determine Content Type
    switch ($ext) {
      case "pdf": $ctype="application/pdf"; break;
      case "exe": $ctype="application/octet-stream"; break;
      case "zip": $ctype="application/zip"; break;
      case "doc": $ctype="application/msword"; break;
      case "xls": $ctype="application/vnd.ms-excel"; break;
      case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
      case "gif": $ctype="image/gif"; break;
      case "png": $ctype="image/png"; break;
      case "jpeg":
      case "jpg": $ctype="image/jpg"; break;
      default: $ctype="application/force-download";
    }

    header("Pragma: public"); // required
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private",false); // required for certain browsers
    header("Content-Type: $ctype");
    header("Content-Disposition: attachment; filename=\"".$_REQUEST["isim"]."\";" );
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: ".$fsize);
    ob_clean();
    flush();
    readfile( $fullPath );

  } else
    die('File Not Found');

}

这是强制 jpg 下载文件。但是这个文件可以下载所有的.php文件。

我通常使用这个下载链接和下载图片; http://domain.net/download.php?file=wp-content/uploads/2016/04/10/126379-fantasy_art.jpg

但后来我测试了这个链接下载我的配置文件... http://domain.net/download.php?file=wp-config.php

我认为这很容易受到攻击。

我该如何解决这个问题?我不想下载任何 .php 文件...

谢谢..

【问题讨论】:

  • “我认为这很容易受到攻击。”是的……是的,非常。很好,你抓住了它。最简单的解决方案是确保只有某个目录中的文件是可以的,并在发回任何内容之前匹配$fullPath 变量。

标签: php wordpress


【解决方案1】:

在你的 switch case 中使用默认值来避免这个问题:

删除这个:

default: $ctype="application/force-download";

为此:default: die('File not found');default: return false;

您还可以检查路径是否有意义,例如它应该是uploads 的子文件夹。这篇文章有一些信息给你:Test if a directory is a sub directory of another folder

【讨论】:

  • 谢谢伙计。我添加“默认:死('找不到文件');”现在效果很好。非常感谢!
  • 谢谢伙计。我替换“默认:死('找不到文件');”这段代码。现在工作正常...
【解决方案2】:

我认为您最好退后一步考虑一下这个脚本的实际作用,因为它仍然是一个巨大的安全漏洞。它的作用如下:

  1. 接受用户的输入(总是不可信的)
  2. 根据一小部分可能的扩展名查看是否允许扩展名
  3. 如果是这样,请将其传递给用户

现在您已经为无法识别的文件扩展名而死,它不会让他们下载您的实际 php 文件。但它仍然会让用户做各种可怕的事情,所有这些都归结为一个非常关键的问题:

您不会尝试验证所请求的文件是否确实适合该人查看!!!

关键点是 readfile() 不关心文件在哪里。它甚至不假定该文件位于您网站的公共目录中。它从您的网络目录下载文件的唯一原因是因为您没有以斜杠开头文件名。但是, readfile() 将愉快地传递服务器上它具有读取权限的任何内容。如果没有您最近的更改,用户也可以轻松做到这一点:

http://domain.net/download.php?file=/etc/passwd

此外,它甚至不必是服务器上的实际文件。在大多数 PHP 安装中,PHP 会愉快地将 URL 作为实际文件加载。所以有人也可以使用你的脚本作为代理:

http://domain.net/download.php?file=http://theFBIwillArrestYouIfYouLoadThis.com/secrets.pdf

这种漏洞(将脚本用作代理的能力)仍然存在于您当前的解决方案中。每当我看到一个网站采用这样的文件路径时,我喜欢看看它能让我逃脱多少。在最坏的情况下,你可能会让自己陷入一个充满伤害的世界。

您必须从纵深防御的场景中来看待它。它归结为黑名单(不允许用户做什么)和白名单(应该允许这个用户做什么)之间的区别。良好的安全实践完全依赖于后一种思维方法,因为不可能提出一个涵盖所有可能情况的完全详尽的黑名单。

在这种情况下,如果您希望用户能够下载文件,您需要某种允许下载的文件列表。一个示例是将任何应该下载的文件放置到特定目录中。如果用户请求文件,那么您的脚本可以使用 realpath() 来确保该文件实际上在您的公共目录中,否则禁止下载。尽管如果它们都在一个目录中,您也可以轻松更改网络服务器(例如 apache 或 nginx)中的配置规则,使其自动将“content-disposition:附件”标头添加到该目录中的任何内容。然后你只需要确保你永远不会把错误的文件放在那个公共目录中。

但就我个人而言,我会使用完整的白名单来处理它。我永远不会让某人指定文件名,然后用它来下载文件。相反,我将有一个管理区域来管理标记为下载的文件:允许的文件列表将存储在数据库中并由我管理。当用户下载文件时,他们不会通过指定文件名来下载文件,而是通过从数据库中指定与他们想要下载的文件相对应的 id 来完成(需要一个简单的用户界面来促进这一点)。 ID用于查找文件路径,然后可以安全下载文件。然后,您甚至可以将文件存储在网站公共区域之外的目录中,这样您就可以完全控制谁可以访问这些文件。

最后一个建议对于您正在尝试做的事情可能有点过头了,但不足之处很简单:您必须仔细考虑代码的安全隐患,并确保为用户提供最低限度的权限可能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 2012-08-03
    相关资源
    最近更新 更多