【问题标题】:ASP.Net Core static file security (images specifically)ASP.Net Core 静态文件安全(特别是图片)
【发布时间】:2018-02-02 03:45:54
【问题描述】:

我有一个看起来很常见的问题,但我找不到任何帮助。假设我有一个经过身份验证的用户将私人照片上传到我服务器上的不可浏览文件夹。每个用户在大型文件存储中都有自己的文件夹,例如...

/FileStore/{UserId}/Photos/my_cute_cat.jpg

文件已上传,我会保存照片的缩略图...

/FileStore/{UserId}/Photos/Thumbs/my_cute_cat_thumb.jpg

该用户想要下载他们的照片。没问题...

  • 用户发送下载请求
  • 我授权用户并确保他们拥有该特定照片
  • 我提供文件

我需要在用户仪表板上以普通的旧 img 标签显示缩略图。 /Thumbs/ 文件夹未设置为提供静态图像。我不希望 /thumbs/ 文件夹能够提供静态图像,因为它们应该只对授权用户可见。我该怎么办?

【问题讨论】:

  • 通过授权控制器操作提供缩略图。类似于回答这个问题的东西:stackoverflow.com/questions/186062/… 显然你会调整安全性,但这是一般的想法。
  • 这个想法很简单。每当您想要提供需要授权的文件时,您需要通过 FileActionResult 提供它,同时使用 [Authorize] 属性装饰操作方法。静态文件夹是公开可用的,即它们位于 wwwroot 文件夹中。它们存在安全漏洞。

标签: asp.net .net asp.net-core .net-core


【解决方案1】:

如果它只是一个小拇指指甲,请考虑在此处使用嵌入式 base64 图像并提供更多详细信息: How to display Base64 images in HTML?

您可以通过将文件编码为 base 64 格式作为此处解释的字符串将 base64 传递给视图: http://www.devcurry.com/2009/01/convert-string-to-base64-and-base64-to.html

使用这种方法或什至使用 FileActionResult 通过控制器提供文件的最大缺点是无法使用 CDN 来传递缓存的内容。你可以做些什么来帮助解决这个问题,仍然是静态地提供图像,但给它们提供非常长的随机名称,这是不可猜测的。当有人向您请求图像时,您只需向他们提供无法猜测的 url。

【讨论】:

  • 这如何解决安全问题?提供图像确实不是 OP 的问题。
  • @ChrisPratt 我不明白你怎么看不到它是如何解决问题的?由于他的安全性位于他的控制器层,他想在控制器上做出业务决策,以决定用户是否可以看到图像。由于他是静态地服务它,他无法实现它。我举了一个使用 base64 通过控制器层提供服务的示例,以及另一个通过使 url 不可猜测来静态提供服务的示例(与 facebook 保护其图像的方式相同)。这是工业界的首选方式。
  • @ChrisPratt 我提到 base64 方法的唯一原因是因为 OP 提到他正在提供一个只有 标签的授权页面。如果 OP 直接将 base64 编码的图像放在该页面上而不是引用静态位置,那么它已经毫不费力地解决了他的问题。
  • 我喜欢这种方法。我真的不想使用控制器操作来加载可能是 20 或 30 个图像,同时必须从我的数据库验证访问权限(或设置一些缓存)。
【解决方案2】:

首先,如果一个静态文件不应该对全世界都可用,那么您的网络服务器不应该为它所在的目录提供服务。在这方面没有其他事情可以做。如果提供目录,则图像可能会泄漏。

这就提出了如何允许用户访问它的问题。简单的答案是您需要一个返回图像的授权操作。基本上,这看起来像:

[Authorize]
public async IActionResult Image(string image)
{
    var file = $"/FileStore/{User.Identity.GetUserId()}/Photos/{image}";
    if (!File.Exists(file))
        return NotFound();

    return File(file);
}

现在,很明显,我不知道您的“FileStore”,所以这里的确切代码可能需要更改。一般的想法是,您只需查看该文件是否存在于用户目录下。如果是这样,他们可以拥有它。如果没有,他们不拥有它。您可能还应该添加更多安全性,例如将image 参数限制为仅图像类型,因此有人不能尝试拉任何任意文件。首先,他们仍然必须设法在那里获取一些异常文件,但以防万一最好不要冒险。

退货方法也可能需要更改。现在,我假设服务器的文件系统上有一个文件,所以我只返回一个带有路径的FileResult。如果您从 Azure、AWS 等中的某种存储帐户中提取它,那么您将使用 HttpClient 发出请求,然后您应该将响应直接流式传输到 FileStreamResult

【讨论】:

  • 这意味着所有昂贵的图片下载流量都需要来自他的服务器?由于大多数人使用 CDN 在边缘服务器上交付图像,这是非常糟糕的做法。检查 facebook 如何使用图像 url 中的访问令牌来保护它。 quora.com/…
【解决方案3】:

我没有在 linux 上测试过,但是如果你创建一个存放图片的文件夹,你实际上可以创建一个返回文件的控制器方法。现在,即使您使用从其他方法提供的视图,您仍然可以从该剃刀视图调用此文件方法并显示图像。

在名为 App 的控制器中,我从名为 Documents 的文件夹中提供图像:

public IActionResult File(string id)
    {        
        if (String.IsNullOrEmpty(id))
        {
            return PhysicalFile(Path.Combine(_env.ContentRootPath, "Documents", "Wrong.png"), "image/jpg");
        }

        return PhysicalFile(Path.Combine(_env.ContentRootPath, "Documents", id), "image/jpg");
    }

在剃须刀中(使用一点引导程序):

 <img src="~/App/File/@profilePicture" class="img-fluid" />

使用提供文件的方法的位置。

【讨论】:

    猜你喜欢
    • 2020-08-28
    • 2019-10-26
    • 2018-02-28
    • 2015-01-25
    • 2019-07-02
    • 1970-01-01
    • 2021-05-02
    • 2018-07-11
    • 2018-04-24
    相关资源
    最近更新 更多