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

flo*_*olu 3 acl amazon-s3 amazon-web-services node.js aws-sdk

我正在使用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) {
    // ...
})
Run Code Online (Sandbox Code Playgroud)

正在下载

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

问题

打开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>
Run Code Online (Sandbox Code Playgroud)

我完全没有找到错误。我真的很感谢您的帮助:)

Spe*_*ton 44

这里得到最高支持的答案在技术上是可行的,但并不实用,因为它公开了桶。

我遇到了同样的问题,这是由于用于生成签名 url 的角色造成的。我使用的角色是这样的:

- Effect: Allow
  Action: 
    - "s3:ListObjects"
    - "s3:GetObject"
    - "s3:GetObjectVersion"
    - "s3:PutObject"
  Resource:
    - "arn:aws:s3:::(bucket-name-here)"
Run Code Online (Sandbox Code Playgroud)

但仅存储桶名称还不够,我必须在末尾添加通配符来指定对整个存储桶的访问:

- Effect: Allow
  Action: 
    - "s3:ListObjects"
    - "s3:GetObject"
    - "s3:GetObjectVersion"
    - "s3:PutObject"
  Resource:
    - "arn:aws:s3:::(bucket-name-here)/*"
Run Code Online (Sandbox Code Playgroud)


Rez*_*avi 7

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

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

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

  3. 您的API密钥和机密。

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

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

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket/*"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

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

对于用户和访问密钥许可权(#2),应遵循以下步骤:

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

在此处输入图片说明

2-选择JSON选项卡。

在此处输入图片说明

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

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::YOURBUCKETNAME"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

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

在此处输入图片说明

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

在此处输入图片说明

6单击“添加权限”按钮。

在此处输入图片说明

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

在此处输入图片说明

最后,确保您的存储桶不可从“公共”访问,将正确的内容类型添加到文件中并进行设置 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,
})
Run Code Online (Sandbox Code Playgroud)

  • 此存储桶策略未实现既定目标“我希望客户端能够安全地下载文件”。该存储桶策略使所有文件公开!您的回答非常好,但现在故障排除已完成,最好返回并收紧该策略或添加一条警告,表明它允许每个主体访问 GetObject。 (2认同)

小智 5

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

我的修复方法是将 S3 权限添加到 serverless.yml 文件内的 IAM 角色。

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

添加所有 s3 操作就可以了。这就是 S3 的 IAM 角色

iamRoleStatements:
  - Effect: Allow
      Action:
        - 's3:*'
      Resource:
        - 'arn:aws:s3:::${self:custom.imageBucket}/*'
Run Code Online (Sandbox Code Playgroud)

  • 很好的提示,但它应该在 `provider` 内部,如下所示:`provider: name: aws iamRoleStatements: - Effect: Allow Action: - 's3:*' Resource: - 'arn:aws:s3:::${env :S3_BUCKET_NAME}/*'` (2认同)