AWS S3生成签名的URL``AccessDenied''

时间:2018-10-05 14:06:19

标签: node.js amazon-web-services amazon-s3 aws-sdk acl

我正在使用NodeJs将文件上传到AWS S3。我希望客户端能够安全地下载文件。因此,我正在尝试生成签名的URL,这些URL在一次使用后会过期。我的代码如下:

上传

const s3bucket = new AWS.S3({
    accessKeyId: 'my-access-key-id',
    secretAccessKey: 'my-secret-access-key',
    Bucket: 'my-bucket-name',
})
const uploadParams = {
    Body: file.data,
    Bucket: 'my-bucket-name',
    ContentType: file.mimetype,
    Key: `files/${file.name}`,
}
s3bucket.upload(uploadParams, function (err, data) {
    // ...
})

下载

const url = s3bucket.getSignedUrl('getObject', {
    Bucket: 'my-bucket-name',
    Key: 'file-key',
    Expires: 300,
})

问题

打开URL时,我得到以下信息:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
    <Code>AccessDenied</Code>
    <Message>
        There were headers present in the request which were not signed
    </Message>
    <HeadersNotSigned>host</HeadersNotSigned>
    <RequestId>D63C8ED4CD8F4E5F</RequestId>
    <HostId>
        9M0r2M3XkRU0JLn7cv5QN3S34G8mYZEy/v16c6JFRZSzDBa2UXaMLkHoyuN7YIt/LCPNnpQLmF4=
    </HostId>
</Error>

我绝对找不到错误。我真的很感谢您的帮助:)

7 个答案:

答案 0 :(得分:1)

您的代码正确,请仔细检查以下内容:

  1. 您的存储桶访问策略。

  2. 通过您的API密钥的存储桶权限。

  3. 您的API密钥和机密。

  4. 您的存储桶名称和密钥。

对于存储桶策略,您可以使用以下内容:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket/*"
        }
    ]
}

用您的存储桶名称更改存储桶

对于用户和访问密钥权限(#2),您应该按照以下步骤操作:

1-转到AWS Identity and Access Management(IAM),然后单击“策略”链接,然后单击“创建策略”按钮。

enter image description here

2-选择“ JSON”标签。

enter image description here

3-输入以下语句,确保更改存储桶名称,然后单击“查看策略”按钮。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::YOURBUCKETNAME"
        }
    ]
}

enter image description here

4-输入您的策略名称,然后点击“创建策略”按钮。

enter image description here

5-点击“用户”链接,找到您当前的用户名(您已经具有该用户名的访问密钥和机密)

enter image description here

6-点击“添加权限”按钮。

enter image description here

7-添加我们在上一步中创建的策略并保存。

enter image description here

最后,请确保您的存储桶不可从“公共”访问,将正确的内容类型添加到文件中并设置signatureVersion: 'v4'

最后的代码应该是这样,谢谢@Vaisakh PS:

const s3bucket = new AWS.S3({
    signatureVersion: 'v4',
    accessKeyId: 'my-access-key-id',
    secretAccessKey: 'my-secret-access-key',
    Bucket: 'my-bucket-name',
})
const uploadParams = {
    Body: file.data,
    Bucket: 'my-bucket-name',
    ContentType: file.mimetype,
    Key: `files/${file.name}`,
}
s3bucket.upload(uploadParams, function (err, data) {
    // ...
})
const url = s3bucket.getSignedUrl('getObject', {
    Bucket: 'my-bucket-name',
    Key: 'file-key',
    Expires: 300,
})

答案 1 :(得分:1)

您的代码看起来不错,但是我认为您在创建signatureVersion: 'v4'对象时缺少了s3bucket参数。请尝试以下更新的代码。

const s3bucket = new AWS.S3({
    signatureVersion: 'v4',
    accessKeyId: 'my-access-key-id',
    secretAccessKey: 'my-secret-access-key',
    Bucket: 'my-bucket-name',
})
const uploadParams = {
    Body: file.data,
    Bucket: 'my-bucket-name',
    ContentType: file.mimetype,
    Key: `files/${file.name}`,
}
s3bucket.upload(uploadParams, function (err, data) {
    // ...
})
const url = s3bucket.getSignedUrl('getObject', {
    Bucket: 'my-bucket-name',
    Key: 'file-key',
    Expires: 300,
})

有关signatureVersion: 'v4'的更多信息,请参见以下链接

https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html

您还可以尝试以下创建nodejs的{​​{1}}库

https://www.npmjs.com/package/aws-signature-v4

答案 2 :(得分:1)

如果您的s3文件已加密,请确保您的策略还可以访问加密密钥和相关操作。

答案 3 :(得分:1)

当我在本地测试lambda函数的工作原理时,我遇到了同样的问题,但是在部署之后却无法正常工作。一旦我向lambda函数添加了s3完全访问权限它起作用

答案 4 :(得分:1)

我在使用无服务器框架的应用程序中也遇到了这个问题。

我的修复是向 serverless.yml 文件中的 IAM 角色添加 S3 权限。

我不太确定 s3 是如何生成预签名 URL 的,但事实证明它们会将您的 IAM 角色考虑在内。

添加所有 s3 操作就成功了。这就是 S3 中 IAM 角色的样子?

iamRoleStatements:
  - Effect: Allow
      Action:
        - 's3:*'
      Resource:
        - 'arn:aws:s3:::${self:custom.imageBucket}/*'

答案 5 :(得分:0)

我一直遇到类似的问题,但我的原因是地区设置。 在我们的后端,我们对该应用程序进行了一些配置设置。

其中一个是"region": "us-west-2",因此使用该区域创建了预签名的url,但是当在前端调用该URL时,该区域设置为"us-west-1"

更改为相同即可解决此问题。

答案 6 :(得分:0)

从最近创建的存储桶移动到最近创建的存储桶时,我最近看到了这个问题。

v2的预签名链接(目前)似乎仍然可以在旧的存储桶上运行,而新的存储桶必须使用v4。

修订后的计划– 2020年6月24日之后创建的任何新存储桶都不会 支持SigV2签名的请求,尽管现有存储桶将继续 支持SigV2,同时我们与客户合作,逐步淘汰旧版本 请求签名方法。

即使您可以继续在现有存储桶和SigV2上使用 支持SigV2的AWS区域的子集,我鼓励您 迁移到SigV4,获得了一些重要的安全性和效率 好处。

https://docs.amazonaws.cn/AmazonS3/latest/API/sigv4-query-string-auth.html#query-string-auth-v4-signing-example

我们的解决方案涉及更新AWS开发工具包以默认使用它;我怀疑较新的版本可能已经默认了此设置。

https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-other.html#config-setting-aws-s3-usesignatureversion4