AWS从客户端上传文件到S3

时间:2016-03-24 02:31:45

标签: javascript node.js amazon-web-services amazon-s3

我知道有一些问题。我知道如何使用AWS SDK完成此任务。

但是,我担心的是安全问题。我的计划是生成一个签名的URL,以便用户登录我的网站可以将文件上传到S3。我在服务器端生成此URL(基于Express框架)。

问题:任何有权访问此URL的人都可以将文件上传到我的存储桶。只有登录的用户才能获得这些网址,但任何人都可以使用它们。

有没有办法生成“一次性使用”网址以通过S3进行身份验证?如果没有,是否有一种我可以使用的方法,它不会在客户端显示我的凭据,也不会将文件上传到我的服务器?(我知道,要求太多:/)

4 个答案:

答案 0 :(得分:5)

请求需要身份验证

除非您将资源公开写入,否则S3将要求上传请求包含身份验证信息。身份验证将请求绑定到AWS账户,然后检查它是否有权执行针对资源的请求(授权)。

有关详细信息,请参阅有关身份验证请求的AWS documenation

用于生成身份验证信息的算法的最新版本称为“AWS签名版本4'”。该算法使用帐户的密钥和其他一些数据来生成与请求一起发送的签名。

AWS知道密钥并可以在其末尾重新计算签名。如果签名匹配,则该请求将通过该帐户进行身份验证。

AWS SDK负责使用提供的帐户凭据为您签署请求。 The docs描述了该算法的工作原理,并告诉您如果您真的想要自己如何签署请求。

在服务器端签署S3请求

不是在客户端保留密钥,以便它可以签署对S3发出的请求,您可以代表客户端在服务器上安全地生成签名URL,然后返回给他们直接调用S3从他们的机器。

此方案是the docs中提到的具体用例之一:

  如果您希望您的用户/客户能够使用,那么

[P]重新签名的网址非常有用   将特定对象上传到您的存储桶,但您不需要它们   拥有AWS安全凭据或权限。

     

创建预签名网址时,您必须提供安全保护   凭证,指定存储桶名称,对象密钥,HTTP方法(PUT   上传对象),以及到期日期和时间。

     

预签名网址仅在指定的时间内有效。

预签名请求安全性

预先签名的请求将身份验证签名直接添加到其中。如您所述,获取URL的任何人都可以提出请求。但是,我不能仅仅让这个事实阻止我使用它们;您可以采取一些措施来阻止攻击者使用它。

考虑客户端和服务器之间的以下交互。

Direct File Upload to S3 Sequence Diagram

请求到期

使用Expires Parameter在URL生成时控制到期时间。通过上述流程,URL可以在生成后到期几秒。在此之后,它将不再起作用并被S3拒绝。设置到期时,您需要考虑服务器和用户之间的请求延迟(步骤#5-#7),以及用户和S3(步骤#8)。

在签名中包含文件校验和

使用Body Parameter,您可以指示S3仅允许具有特定MD5校验和的内容。同样,但更安全的是,您可以要求S3根据文件的 SHA256 校验和验证有效负载。

在上面的流程中的步骤#3之后,计算文件的SHA256校验和,并在步骤#4中将其传递给服务器。然后,您可以将其添加到请求中,如下所示:

var req = S3.putObject({ Bucket: bucket_name, Key: file_name });
req.on('build', function() {
  req.httpRequest.headers['x-amz-content-sha256'] = file_sha256;
});
var url = req.presign(url_expiry);

(参考文献:AWS.Request class docsAWS S3 service source code - getSignedUrlREST Common Request Headers

获取上传网址应该要求身份验证

只有您的授权用户才能获得预先签名的上传网址。应该拒绝匿名请求获取上传URL(步骤#4)。

此外,由于这是特权呼叫,因此应审核所有请求(步骤#6)。这样,如果预先签名的请求泄露,您知道谁生成了它,并且可以在必要时采取进一步行动。

使用HTTPS

有两个主要原因可以保护敏感数据,例如客户端和服务器之间传输时的预签名URL,用户名,密码和会话cookie。

它还向客户保证您是您所说的人,而不是攻击者设置的假网站。

答案 1 :(得分:3)

您可以使用PresignedUrlUploadObject来允许用户上传对象。这是一个过期的URL,您可以设置TTL

对于NodeJS,它看起来像这样:

var s3 = new AWS.S3({computeChecksums: true}); // this is the default setting
var params = {Bucket: 'myBucket', Key: 'myKey', Body: 'EXPECTED CONTENTS'};
var url = s3.getSignedUrl('putObject', params);
console.log("The URL is", url);

来自:AWS Docs

答案 2 :(得分:1)

如果用户知道如何查找凭据,则无法阻止您的凭据被用户看到。如果您要将客户端实施到S3直接上传,处理安全性的最佳方法是使用AWS的IAM系统。

您可以使用IAM注册新帐户,只允许此IAM帐户对特定存储桶执行PUT操作,而不是透露您的root帐户或用于在AWS控制台中执行管理任务的任何帐户的密钥和密钥(甚至是特定存储桶中的特定文件目录)。这看起来像是:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1421341195000",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl",
                "s3:PutObjectVersionAcl"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket",
                "arn:aws:s3:::my-bucket/*"
            ]
        }
    ]
}

现在您有一个只能上传到您的存储桶的帐户。它不能列出其中的项目,它不能更新其中的项目,也不能删除其中的项目。最重要的是,此帐户的凭据不能用于操纵任何其他AWS资源。

答案 3 :(得分:0)

(这不是答案,但我无法发表评论......)

应用程序如何?您可以创建一个带有IP或IP范围限制的短TTL的签名URL,如果所有上传到S3的实际上都发生在您的Web服务器上,我认为其他任何人都不能绕过IP限制。

相关问题