Javascript 基于浏览器的上传-AWS S3签名后-验证上传的文件是否正确

Javascript 基于浏览器的上传-AWS S3签名后-验证上传的文件是否正确,javascript,amazon-web-services,amazon-s3,Javascript,Amazon Web Services,Amazon S3,我试图理解如何通知后端用户已将文件及其密钥上载到s3,并防止用户篡改密钥 要上传的文件是私有的,这意味着我将生成签名的GET URL,以便在用户需要时下载这些文件。 我使用boto3来创建预先签名的POST URL,所以我没有使用自制的实现,但这与库无关 我有一个javascript前端和一个后端API,用于上传文件的用户流大致如下: 浏览器->API(获取/签名): 请求: 答复: 后端使用文件名计算一个随机密钥(以避免冲突),然后使用ACCESS\u密钥、SECRET\u密钥、

我试图理解如何通知后端用户已将文件及其密钥上载到s3,并防止用户篡改密钥

要上传的文件是私有的,这意味着我将生成签名的GET URL,以便在用户需要时下载这些文件。 我使用boto3来创建预先签名的POST URL,所以我没有使用自制的实现,但这与库无关

我有一个javascript前端和一个后端API,用于上传文件的用户流大致如下:

  • 浏览器->API(获取/签名):
    • 请求:
    • 答复:
      • 后端使用文件名计算一个随机密钥(以避免冲突),然后使用ACCESS\u密钥、SECRET\u密钥、BUCKET\u名称和一些其他信息计算签名,将所需参数发送回前端
      • 后端不会在其数据库中保存任何数据,因为在客户端上载文件之前没有实际数据
  • 浏览器->s3(发布mybucket.s3.amazonaws.com):

    • 请求:

      • 浏览器将实际文件和签名参数作为多部分/表单数据发送
    • 答复(文件和邮件):

      • 在标题和正文中,我们有:
        • 水桶
        • 钥匙
        • ETag(它“是对象的MD5哈希”)
        • 位置
许多javascript库和指南(即)现在只是将键从POST响应代理到后端。然后后端检查文件是否存在,并将新的文件密钥添加到其数据库中

现在,要上传的文件是私有的,这意味着我将生成签名的GET URL,以便在用户需要时下载文件。 假设有UserAUserBUserB上传了FileB。 是什么阻止了UserA上传文件,但却向后端发送了FileB密钥(可以猜测,或者只是随机输入,直到它们得到某个存在的文件),从而后端保存了UserA拥有的FileB

我想到的是:

  • 密钥是随机的,一个密钥/文件只能属于一个用户,因此当userA告诉“我上传了fileB”时,后端会响应“fileB是另一个用户的”/“错误”。在我看来,这似乎是解决问题的最简单方法,但我认为我遗漏了一些东西(并发性、遗留文件等)
  • 在获取/签名后端存储“UserA将上载FileA”,因此在回调上,如果“Error”不匹配,后端将检查UserA是否希望上载FileA
  • 检查s3返回的ETag,这样他们就必须有文件来计算其md5,而用户无法获得FileB
  • 在策略中设置密钥为XXXX,并在回调上重新计算签名并检查签名是否相同
  • 使用临时上传桶,以便恶意用户不仅需要猜测随机密钥,还需要猜测该密钥是正在上载的文件的密钥。调用回调时,后端会将具有指定键的文件移动到最终存储桶
也许我忽略了一些东西,但除了(我认为)黑客的解决方案(设置以用户名开始的键,…),我在网上找不到任何解决方案


我不能发布两个以上的链接,因此一些aws文档被遗漏了。

您的第二个建议方法已步入正轨。您必须在服务器上保存已签名的URL到用户的映射(您可以使用诸如redis之类的键值存储),然后在上载之后,将来自客户端的密钥与存储在服务器上的密钥进行比较。
{
  filename: 'something.txt
  size: 12345
  type: image/jpeg
}
{
    url: https://mybucket.s3.amazonaws.com
    fields: {
        acl: 'private',
        key: 'mykey', 
        signature: 'mysignature', 
        policy: 'mybase64 encoded policy'
    }
}
{
        acl: 'private',
        key: 'mykey', 
        signature: 'mysignature', 
        policy: 'mybase64 encoded policy'
}