保持上传的文件安全,但仍然可以通过https

时间:2015-12-16 21:35:53

标签: php security laravel image-uploading

我正在编写一个允许用户上传图像的应用程序(php / laravel)。简单。没问题。过去,每当我编写这样的应用程序时,用户可以上传图片,但只有上传图片的用户才能访问这些图片,我创建了一个公开的上传文件。 Web服务器主目录中的目录。在这个上传目录中,我包含了一个只显示一条消息的index.html文件:"该目录的内容被隐藏"。

如果用户从Web浏览器手动浏览到uploads目录,这会阻止用户查看文件的内容。然后作为另一层"安全"我会将一个随机字符集的md5哈希附加到文件名中。文件名最终会像:

my_image__5a73e7b6df89f85bb34129fcdfd7da12.png

这使得任何人都不可能猜到上传目录中的特定文件名。

这仍然是实现此类功能的最佳方式吗?我的过程中是否有一些漏洞?出于某种原因,将敏感文件放在webroot中是不对的......

2 个答案:

答案 0 :(得分:2)

我将所有图像存储在webroot之外。对于每个图像,您在包含的数据库中都有一条记录 有关谁可以访问该图像的信息,图像的名称以及图像的完整路径。

要显示实际图像,您需要创建一个额外的图像路径,该路径将进入该目录并创建适当的响应。如果添加干预包,这实际上非常简单。

Route::get('images/{imageName}', function($imageName) {
    // Check database to ensure currently logged in user has acces to the image.
    $image = DB::table('images')->where('name', $imageName)->where('user', Auth::user()->user_name)->first();
    if(!is_null($image)) {
        return Image::make($image->full_path)->response('png');
    } else {
        return Image::make('defaultNotAllowedImage.png')->response('png');
    }
});

现在如果他们调用images / someTestImage.png和someTestImage.png匹配图像的名称和用户,它将返回 该图像,否则将返回默认图像。

答案 1 :(得分:1)

这就是我的所作所为:

上传目录在网络根目录外。没有索引文件 我随机化文件名。 我使用应用程序逻辑来确定谁可以看到什么,然后将图像数据发送到浏览器:

public function images($dir, $image_filename)
{
     $allowed_dirs = array(
       //some directories I know files in for 
       //a small amount of security
     } 

      //check if user is allowed to view the passed image

     $user = $this->user;
     $this->validate_user($user);  
     if (array_key_exists($dir, $allowed_dirs)) { //is $dir allowed?
        $path = BASEPATH . $allowed_dirs[$dir];
        $details = @getimagesize($path . '/' .  basename($image_filename));

        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); 
        header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
        header("Pragma: no-cache"); 
        header('Content-Type: ' . $details['mime']);
        @readfile($path . '/'  . $image_filename); //send image data to browser
        exit();
     }
     else {
        exit();
     }
}