使用预签名的 url PUT 到 S3 会出现 403 错误

Posted

技术标签:

【中文标题】使用预签名的 url PUT 到 S3 会出现 403 错误【英文标题】:PUT to S3 with presigned url gives 403 error 【发布时间】:2018-07-06 16:58:53 【问题描述】:

我正在使用 Node 获取 S3 的预签名 RUL,以便将图像放入 S3 存储桶。

var aws = require('aws-sdk');
// Request presigned URL from S3
exports.S3presignedURL = function (req, res) 
  var s3 = new aws.S3();
  var params = 
    Bucket: process.env.S3_BUCKET, 
    Key: '123456', //TODO: creat unique S3 key
    //ACL:'public-read',
    ContentType: req.body['Content-Type'], //'image/jpg'
  ;
  s3.getSignedUrl('putObject', params, function(err, url) 
      if(err) console.log(err);
      res.json(url: url);
  );
;

这成功检索了表单的预签名 url...

https://[my-bucket-name].s3.amazonaws.com/1233456?AWSAccessKeyId=[My-ID]&Expires=1517063526&Signature=95eA00KkJnJAgxdzNNafGJ6GRLc%3D (我必须包含过期标头吗?)

回到客户端(Web 应用程序),我使用 Angular 生成 HTTP 请求。我同时使用了 $http 和 ngFileUpload,但同样没有成功。这是我的 ngFileUpload 代码。

Upload.upload(
    url: responce.data.url, //S3 upload url including bucket name
    method: 'PUT',
    'Content-Type': file.type, //I have tried putting the ContentTyep header all over
    headers:  
        //'x-amz-acl':'public-read',
        'Content-Type': file.type, 
    , 
    data:  
        file: file,
        headers:'Content-Type': file.type,
    ,                         
)

然而,似乎无论我如何格式化我的标题,我总是得到一个 403 错误。在它说的错误的 XML 中,

SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.

我认为 CORS 不是问题。最初我遇到了一些 CORS 错误,但它们看起来不同,我让它们离开了对 S3 存储桶 CORS 设置的一些更改。我已经为 presignedURL 的请求和对 S3 的 PUT 请求尝试了很多标头的试错设置,但我似乎找不到正确的组合。

我确实注意到,当我控制台记录 403 响应错误时,字段

config.headers:Content-Type: undefined, __setXHR_: ƒ, Accept: "application/json, text/plain, */*"

这是说没有设置 Content-Type 头吗?当我在任何我认为可能的地方设置标题时,这怎么可能?无论如何,我的头撞到了墙上……


编辑:根据要求,我当前的 CORS。 (我把所有的东西都扔进去了,以摆脱我之前收到的 CORS 警告。只有在我的上传工作正常后,我才会把它削减到基本要素。)

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedOrigin>http://localhost:9500</AllowedOrigin>
    <AllowedOrigin>https://localhost:9500</AllowedOrigin>
    <AllowedOrigin>http://www.example.com</AllowedOrigin>
    <AllowedOrigin>https://www.example.com</AllowedOrigin>
    <AllowedOrigin>http://lvh.me:9500</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
    <AllowedHeader>Content-Type</AllowedHeader>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>

【问题讨论】:

您需要更多的调试日志记录。例如,记录file.type 的值。 @Michael-sqlbot 是的,我已经记录了所有内容,但为了简洁起见,我将它们删除了。 file.type 记录“images/png” 显示您当前的存储桶 CORS 配置? 我遇到了类似的错误。你发现了吗? 我没有。如果你这样做,请告诉我。 【参考方案1】:

面临同样的问题。发现我用来创建预签名 URL 的内容类型与我发送到 S3 的对象的内容类型不匹配。我建议您在创建预签名 URL 时添加 Expiration 标头(我也这样做了),并在控制台中准确检查在您对 S3 执行 put 时发送的内容类型。此外,数据只需要是文件,而不是您在那里创建的结构。

【讨论】:

谢谢。内容类型有同样的问题。 谢谢!你救了我的命。【参考方案2】:

我遇到了签名不匹配的 403 错误,我一生都无法弄清楚原因。阅读其他一些示例,其中一个说它必须在 us-east-1 中运行,因为其他地区不支持它。我在 us-east-2 中,已切换并且完全相同的代码有效。

尝试使用 us-east-1

【讨论】:

奇怪的是只在一个特定的地区工作,有没有人有类似的经历?

以上是关于使用预签名的 url PUT 到 S3 会出现 403 错误的主要内容,如果未能解决你的问题,请参考以下文章

使用预签名 URL 上传到 S3 存储桶会出现 403 禁止错误

使用预签名的 url 将文件发送到 s3 存储桶会出现 403 错误 (SignatureDoesNotMatch)

NS-Vue/Rails 对 S3 存储桶的预签名 PUT 请求给出 403

AWS S3 通过预签名 URL 上传返回 400 错误请求

放入 S3 预签名 URL 时如何修复“403 Forbidden”

使用预签名 URL 将文件上传到 Amazon S3 时出现 CORS 错误