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


Force image download - .php files 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文件。

我通常使用这个下载链接和下载图片;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文件。。。

谢谢。。

在交换机情况下使用默认值来避免此问题:

删除此:

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

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

您还可以检查路径是否有意义,比如它应该是uploads的子文件夹。这篇文章为您提供了一些信息:测试一个目录是否是另一个文件夹的子目录

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

  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()来确保该文件实际上在您的公共目录中,否则将禁止下载。尽管如果它们都在一个目录中,您也可以很容易地更改Web服务器(如apache或nginx)中的配置规则,使其自动将"内容处置:附件"标头添加到该目录中的任何内容。然后你只需要确保你永远不会把错误的文件放在公共目录中。

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

最后一个建议可能对你想要做的事情来说有些过头了,但简而言之:你必须仔细考虑代码的安全影响,并确保给用户尽可能少的特权。