AWS S3 - PUT to URL from getSignedUrl() returns 403 SignatureDoesNotMatch error

六月ゝ 毕业季﹏ 提交于 2020-01-24 21:33:32

问题


This problem has been driving me nuts for two days now.

The objective: Upload an image directly from the browser to S3 via a pre-signed URL supplied by the getSignedUrl function in the AWS Javascript SDK.

I haven't had any problems generating URLs with getSignedUrl. The following code...

const params = {
  Key:         key,
  Bucket:      process.env.S3_BUCKET,
  ContentType: "image/jpeg"
};

S3.getSignedUrl("putObject", params, callback);

...yields something like:

https://s3.amazonaws.com/foobar-bucket/someImage.jpeg?AWSAccessKeyId=ACCESSKEY123&Content-Type=image%2Fjpeg&Expires=1543357053&Signature=3fgjyj7gpJiQvbIGhqWXSY40JUU%3D&x-amz-acl=private&x-amz-security-token=FQoGZXIvYXdzEDYaDPzeqKMbfgetCcZBaCL0AWftL%2BIT%2BP3tqTDVtNU1G8eC9sjl9unhwknrYvnEcrztfR9%2FO9AGD6VDiDDKfTQ9SmQpfXmiyTKDwAcevTwxeRnj6hGwnHgvzFVBzoslrB8MxrxjUpiI7NQW3oRMunbLskZ4LgvQYs8Rh%2FDjat4H%2F%2BvfPxDSQUSa41%2BFKcoySUHGh2xqfBFGCkHlIqVgk1KELDHmTaNckkvc9B4cgEXmAd3u1f1KC9mbobYcLLRPIzMj9bLJH%2BIlINylzubao1pCQ7m%2BWdX5xAZDhTSNwQfo4ywSWV7kUpbq2dgEriOiKAReEjmFQtuGqYBi3t2dhrasptOlXFXUozdz23wU%3D

But uploading an image via PUT request to the provided URL always returns a 403 SignatureDoesNotMatch error from S3.

What DOES work:

  • Calling getSignedUrl() from a local instance of AWS Lambda (via serverless-offline).

What DOESN'T work:

  • Setting the query string variables as headers (Content-Type, x-amz-*, etc.)
  • Removing all headers
  • Changing the ACL when getting the URL (private, public-read-write, no ACL, etc.)
  • Changing the region of aws-sdk in Node
  • Trying POST instead of PUT (it's worth a shot)

Any help on this issue would be greatly appreciated. I'm about to throw my computer out the window and jump out after it in frustration if this continues to be a problem, as it simply does NOT want to work!


回答1:


I figured it out. The Lambda function invoking getSignedUrl() did not have the correct IAM role permissions to access the S3 bucket in question. In serverless.yml...

iamRoleStatements:
    - Effect: Allow
      Action:
        - s3:*
      Resource: "arn:aws:s3:::foobar-bucket/*"

I wouldn't actually use a wildcard here, but you get the picture. The fact that getSignedUrl() still succeeds and returns a URL even when the URL is doomed to fail because of missing permissions is extremely misleading.

I hope this answer helps some confused soul in the future.




回答2:


It worked for me doing it in the old school way: (axios kept giving 403 Forbidden)

  const xhr = new XMLHttpRequest();
  xhr.open("PUT", signedRequest);
  xhr.onreadystatechange = () => {

    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        //Put your logic here..
         //When it get's here you can access the image using the url you got when signed.
      }    
    }
  };
  xhr.send(file);

Notice this needs to run from the client, so you will need to configure the Cross Origin Police in your Bucket.



来源:https://stackoverflow.com/questions/53508691/aws-s3-put-to-url-from-getsignedurl-returns-403-signaturedoesnotmatch-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!