确保上传的文件安全,但仍可通过 https 访问
Keeping uploaded files secure but still available via https
我正在编写一个允许用户上传图片的应用程序 (php/laravel)。简单的。没问题。过去每当我编写这样的应用程序时,用户可以在其中上传图像,但它们只能由上传图像的用户访问,我在网络服务器的主目录中创建了一个 public 'uploads' 目录.在这个上传目录中,我包含了一个 index.html 文件,它只显示一条消息:"The contents of this directory are hidden".
如果用户从 Web 浏览器手动浏览到上传目录,这会阻止用户看到文件的内容。然后作为 "security" 的附加层,我会将一组随机字符的 md5 哈希附加到文件名。文件名最终看起来像:
my_image__5a73e7b6df89f85bb34129fcdfd7da12.png
这使得任何人极不可能猜出上传目录中的特定文件名。
这仍然是实现此类功能的最佳方式吗?我在过程中是否忽略了一些漏洞?出于某种原因,将敏感文件放在 webroot 中感觉不对...
这是我的做法:
上传目录在网络根目录之外。没有索引文件。
我随机化文件名。
我使用应用程序逻辑来确定谁可以看到什么,然后将图像数据发送到浏览器:
即
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();
}
}
我会将所有图像存储在 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 匹配图像名称和用户,它将 return
该图像,否则它将 return 默认图像。
我正在编写一个允许用户上传图片的应用程序 (php/laravel)。简单的。没问题。过去每当我编写这样的应用程序时,用户可以在其中上传图像,但它们只能由上传图像的用户访问,我在网络服务器的主目录中创建了一个 public 'uploads' 目录.在这个上传目录中,我包含了一个 index.html 文件,它只显示一条消息:"The contents of this directory are hidden".
如果用户从 Web 浏览器手动浏览到上传目录,这会阻止用户看到文件的内容。然后作为 "security" 的附加层,我会将一组随机字符的 md5 哈希附加到文件名。文件名最终看起来像:
my_image__5a73e7b6df89f85bb34129fcdfd7da12.png
这使得任何人极不可能猜出上传目录中的特定文件名。
这仍然是实现此类功能的最佳方式吗?我在过程中是否忽略了一些漏洞?出于某种原因,将敏感文件放在 webroot 中感觉不对...
这是我的做法:
上传目录在网络根目录之外。没有索引文件。
我随机化文件名。
我使用应用程序逻辑来确定谁可以看到什么,然后将图像数据发送到浏览器:
即
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();
}
}
我会将所有图像存储在 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 匹配图像名称和用户,它将 return 该图像,否则它将 return 默认图像。