强制图像下载 - .php文件下载

时间:2016-05-11 17:31:58

标签: php wordpress

这是我的download.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文件。

Normaly我使用此下载链接并下载图像; 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文件...

谢谢..

2 个答案:

答案 0 :(得分:1)

在交换机机箱中使用默认值可以避免此问题:

删除它:

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

答案 1 :(得分:0)

我认为退一步考虑一下这个脚本实际上做了什么会很好,因为它仍然是一个巨大的安全漏洞。这是它的作用:

  1. 取用户的输入(总是不值得信任)
  2. 根据可能的扩展名列表
  3. 查看是否允许扩展名
  4. 如果是,请将其传递给用户
  5. 现在你已经死了无法识别的文件扩展名,它不会让他们下载你真正的php文件。但它仍会让用户做各种可怕的事情,所有这些都归结为一个非常关键的问题:

    您没有尝试验证所请求的文件是否真正合理,以供该人查看!!!

    关键是readfile()并不关心文件的位置。它甚至不假设该文件位于您网站的公共目录中。从web目录下载文件的唯一原因是因为你没有用斜杠启动文件名。但是,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),以便自动添加内容配置:附件'标题到该目录中的任何内容。然后你必须确保你永远不会把错误的文件放在那个公共目录中。

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

    最后一个建议可能对你要做的事情有些过分,但缺点很简单:你必须仔细考虑你的代码的安全隐患,并确保你给用户最少的权限可能的。