如何使托管在 Amazon S3 上的图像不那么公开但不完全私有?

Posted

技术标签:

【中文标题】如何使托管在 Amazon S3 上的图像不那么公开但不完全私有?【英文标题】:How to make images hosted on Amazon S3 less public but not completely private? 【发布时间】:2011-02-02 17:35:43 【问题描述】:

我启动了一个使用 Amazon S3 进行图像托管的示例应用程序。我设法哄它工作。该应用程序托管在github.com。该应用程序允许您使用个人资料照片创建用户。当您上传照片时,Web 应用程序会将其存储在 Amazon S3 而不是您的本地文件系统上。 (如果您在 heroku.com 主持,这非常重要)

但是,当我在页面的浏览器中执行“查看源代码”时,我注意到图片的 URL 是我分配给应用程序的 S3 存储桶中的 Amazon S3 URL。我剪切并粘贴了 URL,并且能够在同一个浏览器中查看图片,并且在另一个浏览器中,我没有打开我的 Web 应用程序或 Amazon S3 的会话。

有没有什么方法可以限制对该 URL(和图像)的访问,以便仅登录到我的应用程序的浏览器可以访问它?

我发现的有关 Amazon ACL 的大部分信息仅涉及所有者或通过 Amazon 或 AmazonS3 进行身份验证的用户组或匿名所有人的访问权限。

编辑----2010 年 7 月 7 日更新

亚马逊有just announced 更多方法来限制对 S3 对象和存储桶的访问。除其他方式外,您现在可以通过限定 HTTP 引用者来限制对 S3 对象的访问。这看起来很有趣……我等不及他们更新他们的开发者文档了。

【问题讨论】:

【参考方案1】:

对于隐私实际上很重要的文件,我们会按如下方式处理:

文件使用私有 ACL 存储,这意味着只有授权代理才能下载(或上传)它们 要访问文件,我们链接到http://myapp.com/download/s3-path,其中download 对应于控制器(在MVC 意义上) 适当实施 ACL,以便只有登录用户才能访问该控制器/操作 该控制器使用 API 下载文件,然后使用正确的 mime 类型、缓存头、文件大小等将其流式传输给用户。

使用这种方法,您最终会使用比您需要的更多的带宽,但您仍然可以节省存储空间。对我们来说,这是可行的,因为我们往往比带宽更快地耗尽存储空间。

对于仅涉及隐私的文件,我们会生成用于 URL 的随机哈希。这基本上是通过默默无闻的安全性,你必须小心你的哈希很难猜到。

但是,当我在页面的浏览器中执行“查看源代码”时,我注意到图片的 URL 是我分配给应用程序的 S3 存储桶中的 Amazon S3 URL。我剪切并粘贴了 URL,并且能够在同一个浏览器中查看图片,并且在另一个浏览器中我没有打开我的 Web 应用程序或 Amazon S3 的会话。

请记住,这与存储在文档根目录中其他位置的任何图像没有什么不同。您可能需要也可能不需要您正在寻找的那种安全性。

【讨论】:

如果你真的需要ACL,这绝对是怎么做的。但是,在 Heroku 上,根据这些资产的访问模式,此策略将迫使您比其他方式更快地“启动您的 dynos”。 正义:不过,我不确定这是否比将文件存储在本地并通过应用程序流式传输更糟糕。如果您想以任何重要的方式锁定文件,通过应用程序流式传输基本上是唯一的解决方案。当然,很少有应用程序有这种要求。我也习惯于在专用服务器环境中工作,所以我的建议可能不适用于 heroku。 感谢您提供非常完整的答案。 我想询问更多关于“该控制器使用 API 下载文件,然后使用正确的 mime 类型、缓存头、文件大小等将其流式传输给用户”。所以您的应用程序会将文件下载到您的应用程序服务器中,然后从您的应用程序服务器将该文件提供给应用程序用户?或者您的下载/s3-path 是否显示包含时间到期链接的网页?喜欢这个docs.aws.amazon.com/AmazonS3/latest/dev/S3_QSAuth.html【参考方案2】:

Amazon 的 Ruby SDK (https://github.com/aws/aws-sdk-ruby) 有一些有用的方法可以让您轻松完成这项工作。 “url_for”可以为原本私有的 S3 对象生成一个临时可读的 URL。

以下是创建 5 分钟后过期的可读 URL 的方法:

object = AWS::S3.new.buckets['BUCKET'].objects['KEY']

object.url_for(:read, :expires => 300).to_s

AWS 文档: http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html#url_for-instance_method

【讨论】:

它们在 php SDK 中具有类似的签名 URL 功能。 docs.aws.amazon.com/aws-sdk-php/guide/latest/…我认为这是解决此海报问题的最佳当前解决方案。【参考方案3】:

S3 是一项单独的服务,不知道您的会话。

通用解决方案是认识到为每个资产分配一个单独的、唯一的、非常长且随机的密钥(构成该资产的 URL 的一部分)的好处和安全属性。如果您愿意,您甚至可以分配一个具有 512 个有效随机位的密钥,并且该 URL 将在很长一段时间内保持不可猜测。

因为在时间 t 有权访问资产的人可以简单地复制资产以供将来参考,因此允许该人知道 URL 并随时访问资产是有意义的。 同样,由于该人可以简单地下载资产并将其分发给其他人,因此允许该人将 URL 分发给其他人是有意义的,否则他只会将资产本身分发给其他人。 由于所有此类访问都是只读的,并且由于写入仅限于网站服务器,因此不存在任何拥有此访问权限的人的恶意“黑客攻击”风险。

您必须确定这是否足够安全。如果不是,那么 S3 可能不适合您,也许您需要将图像作为二进制列存储在数据库中并将它们缓存在 memcached 中,您可以在 Heroku 上执行此操作。

【讨论】:

@Justice - 感谢您提供完整且非常合理的答案。这正是我使用 S3 所需的推理。就隐私而言,存储在 S3 上的资产并不是非常重要的,并且 URL 仅对登录用户可用。我想我必须做某种加盐哈希来生成随机数。 +1 表示逻辑点。为资源的每次更新生成一个新的随机 URL 也很重要。【参考方案4】:

我认为你能做的最好的就是 drop.io 所做的。虽然数据原则上任何人都可以访问,但您给它一个大而随机的 URL。知道该 URL 的任何人都可以访问它,但您的应用程序控制谁可以看到该 URL。

一种通过默默无闻的安全性。

您可以将其视为 URL 中包含的密码。这意味着如果您认真对待安全性,则必须将 URL 视为机密信息。 您必须确保这些链接也不会泄露给搜索引擎。

撤销访问权限也很棘手。您唯一能做的就是使 URL 无效并分配一个新 URL。

【讨论】:

以上是关于如何使托管在 Amazon S3 上的图像不那么公开但不完全私有?的主要内容,如果未能解决你的问题,请参考以下文章

您如何使托管在 S3 上的静态站点的 index.html 缓存失效?

如何在 Namecheap 为 Amazon S3 设置 CNAME

在 Amazon S3 中托管静态网站而不使用 Amazon 路由 53

Amazon S3 静态 Web 托管不适用于自定义域名(点问题)

使用 Amazon S3 和 Cloudfront 的 CORS

如何使用 PHP 显示来自 Amazon S3 的图像?