这是我的下载.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
的子文件夹。这篇文章为您提供了一些信息:测试一个目录是否是另一个文件夹的子目录
我认为退一步考虑一下这个脚本的实际功能会很好,因为它仍然是一个巨大的安全漏洞。它的作用如下:
- 接受用户的输入(这总是不可信的)
- 根据可能的扩展的小列表,查看是否允许其扩展
- 如果是,则将其传递给用户
现在你已经为无法识别的文件扩展名而死了,它不会让他们下载你真正的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用于查找文件路径,然后可以安全地下载文件。然后,你甚至可以将文件存储在网站公共区域之外的目录中,这样你就可以完全控制谁可以访问这些文件。
最后一个建议可能对你想要做的事情来说有些过头了,但简而言之:你必须仔细考虑代码的安全影响,并确保给用户尽可能少的特权。