我们正在开发一款 Web 应用,其中(除其他功能外)我们的用户可以上传文件。但是,由于存储空间有限,我们无法将这些文件存储在我们的 VPS 上,因此我们决定使用 S3。
主要问题是我们必须确保用户只能访问他们自己的数据。因此,我们在数据库中保存文件列表,以及有权访问这些文件的用户列表。我们的服务器可以轻松确定用户是否有权访问文件。但如何真正将文件提供给用户呢?
我已经考虑过一些可能性,但实际上它们似乎都不是最好的。
1. 使用 PHP 生成(过期)签名 URL
这是一个非常简单的方法,它也很快,但会导致非常非常丑陋和很长的 URL。
2. 混淆的 URL
这意味着,我们将文件公开保存在 S3 上供读取,但所有文件都存储在难以猜测的文件夹中,例如:24fa0b8ef0ebb6e99c64be8092d3ede20000
。然而,这可能不是最安全的方法。即使您永远猜不到文件夹名称,但在您知道它之后(因为您实际上有权访问它),您可以与任何人(任何未经授权的人)共享该链接。
3.通过我们的服务器下载文件
这意味着文件不直接由 S3 提供,但我们的服务器首先会安全地读取并提供服务。我们真的不希望这样 :)
4. 检查引荐来源
这模糊化的 URL可以通过“确保”请求来自我们的服务器(您可以设置 S3 来检查 referrer)来改进解决方案。然而,这是一个非常不可靠的解决方案,因为并非所有浏览器都会发送 referrer 数据,而且这些数据也可能是伪造的。
有什么好方法可以安全地为不同的客户端提供来自 Amazon S3 的文件?
答案1
这对您来说确实接近于“做我的系统架构”,但您的四个想法是可变安全性方面的有趣案例研究,因此让我们运行您的选项并看看它们的表现如何:
4. 检查引荐来源
引荐来源由客户端提供。信任客户端提供的身份验证/授权数据几乎会使安全性失效(我只能声称自己是从您期望我来自的地方发送的)。
结论: 可怕的想法——很容易绕过。
3.通过我们的服务器下载文件
这不是一个坏主意,只要您愿意花费带宽来实现它,并且您的服务器可靠。
假设您已经解决了常规服务器/应用程序的安全问题,那么这是您提出的选项中最安全的。
结论:不错的解决方案。非常安全,但如果带宽是一个因素,则可能不是最佳方案。
2. 混淆的 URL
通过隐蔽性实现安全?真的吗?不。
我甚至不会去分析它。真的吗?
结论:如果 #4 是可怕的这是恐怖分子因为人们甚至不必费力伪造引荐来源标头。猜出字符串并赢得所有数据的奖品!
1. 使用 PHP 生成(过期)签名 URL
此选项的吸血系数相当低。
任何人都可以点击 URL 并窃取数据,这是安全方面的禁忌,但您可以通过使链接过期来缓解这种情况(只要链接寿命足够短,漏洞窗口就很小)。URL
过期可能给那些想要长时间保留下载链接或无法及时获取链接的用户带来不便——这有点损害用户体验,但可能是值得的。
结论:不如#3,但如果带宽是一个主要考虑因素,它肯定比#4 或#2 要好。
我会做什么?
鉴于这些选项,我会选择 #3 — 通过您自己的前端服务器传递文件,并以您的应用程序通常的方式进行身份验证。假设您的正常安全性相当不错,从安全角度来看,这是最佳选择。
是的,这意味着您的服务器将使用更多带宽,并且有更多资源充当中间人 — 但您总是可以为此多收取一点费用。
答案2
使用Amazon S3 预签名查询在完成您希望的任何用户验证后,直接向用户提供 S3 对象。此方法会创建一个有时间限制的 URL,您可以将用户重定向到该 URL。
答案3
还有另一种方法。
您可以将 AWS CloudFront 指向您的 S3 存储桶并使用签名的 Cookies 向您的最终用户安全地提供内容。
最终用户需要登录您的服务器以获取签名的 Cookie,然后在访问任何文件时将其发送到 CDN。