0

My Request looks like this:

https://{my-bucket-name}.s3.amazonaws.com/{user-id}/{image-name}.jpeg?AWSAccessKeyId={key}&Content-Type=image%2Fjpeg&Expires=1597576628&Signature={signature}

where the {parts} are just censored but in the original response look correct, just like in a tutorial that I am doing.

I have allowed public access and set both CORS (which is why I get the pre-signed URL to upload to in the first place) as well as a bucket policy that contains this:

    {
        "Sid": "{sid}",
        "Action": [
            "s3:GetObject"
        ],
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::{my-bucket-name}/*",
        "Principal": "*"
    }

So what might be the problem?

EDIT: adding PutObject to the policy did not help. I upload the file like this, from the React-client directly:

  const upload = await axios.put(uploadConfig.data.url, file, {
    headers: {
      'Content-Type': file.type
    }
  })

And I generate the pre-signed URL like this (note the putObject operation):

    s3.getSignedUrl('putObject', {
        Bucket: '{my-bucket-name}',
        ContentType: 'image/jpeg',
        Key: key
    }, (err, url) => res.send({key, url}));

Additional request headers set by the middleware/browser are:

Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en,de;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 104221
Content-Type: image/jpeg
Host: {my-bucket-name}.s3.amazonaws.com
Origin: http://localhost:3000
Pragma: no-cache
Referer: http://localhost:3000/blogs/new
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla....
Phil
  • 7,065
  • 8
  • 49
  • 91
  • How do you upload the file with the pre-signed url? – Marcin Aug 16 '20 at 11:28
  • @Phil, I have deleted my answer. it was wrong. because you should never allow public write access. if the IAM credential used to generate the pre-signed url has sufficient permission to upload the file, the pre-signed url should work as well. – Arun Kamalanathan Aug 16 '20 at 11:31
  • also if your pre-signed url is generated for `getObject`, you cannot perform a `putObject` operation using that pre-signed url – Arun Kamalanathan Aug 16 '20 at 11:33
  • @ArunK I am doing this tutorial: https://www.udemy.com/course/advanced-node-for-developers where the teacher explains that the public access is ok, as we want a direct upload from the client, without wasting CPU-time of our backend, during the upload. For me this seems reasonable as long as you check only for file extensions and don't do deep file checks anyway. – Phil Aug 16 '20 at 11:39
  • what i meant was, giving `putObject` permission for every one in the bucket policy is bad. upload using pre-signed url is the correct way. public read is ok if you are ok with sharing your files with the whole world. – Arun Kamalanathan Aug 16 '20 at 11:44
  • @ArunK I am using putObject as the operation to generate the pre-signed URL. Any other ideas what might be the problem? – Phil Aug 16 '20 at 11:54
  • thanks for the update. can you set the content type manually in the axios request to `'Content-Type': 'image/jpeg'`. because i have a feeling that axios might be sending `octet-stream` as the content type . you can log the output of `file.type` to confirm that as well. – Arun Kamalanathan Aug 16 '20 at 11:57
  • just noticed that the additional headers showing that its 'image/jpeg'. did you try to send the request via curl or postman ? – Arun Kamalanathan Aug 16 '20 at 12:16
  • @ArunK Ok, thanks, it seems I have this problem: https://stackoverflow.com/questions/26533245/the-authorization-mechanism-you-have-provided-is-not-supported-please-use-aws4 Sending the request from postman returned more information, Chrome swallowed the error message "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256." – Phil Aug 16 '20 at 12:42
  • thats good. did you try to specify the version as suggested `var s3 = new AWS.S3({signatureVersion: 'v4'});` – Arun Kamalanathan Aug 16 '20 at 13:26

1 Answers1

1

Please use AWS4-HMAC-SHA256. error message suggests to use signature version v4. it appears the generated signature in the pre-signed url is not v4. possibly signature version v2

please try specifying the signature version when generating the URL as below.

const s3 = new AWS.S3({signatureVersion: 'v4'})

Also make sure that you are using aws-sdk version greater than 2.68.0 according to the documentation

Arun Kamalanathan
  • 8,107
  • 4
  • 23
  • 39
  • Thanks, it works now. The v4 I fugured out myself, but the package update saved me some time :) Another thing I had to add was the custom region: `new AWS.S3({ accessKeyId, secretAccessKey, signatureVersion: 'v4', region: 'eu-central-1' });` – Phil Aug 16 '20 at 17:10
  • Yes you have figured the V4. Posted the answer to help others in the same situation. Please post an answer if you would like. – Arun Kamalanathan Aug 16 '20 at 22:09
  • No no, it's alright, as I said, you helped me a lot, all credits to you, thanks :) – Phil Aug 17 '20 at 04:28