Home > Enterprise >  Signature Mismatch error when using S3 Signed URL
Signature Mismatch error when using S3 Signed URL

Time:07-13

I don't know what happened in the last 24 hours that caused this thing to break, but it had been working perfectly for 3 years, non stop without issues. Trust me, I haven't changed any code. As a matter of fact, I haven't pushed code for 2 weeks.

Basically, I am using Laravel 6 and Laravel Vapor to upload files to S3 using the Signed URLs mechanism that the framework provides. Ever since this morning, I am seeing the following issue. The AWS PHP SDK is 3.148.3, by the way.

<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<AWSAccessKeyId>[REDACTED]</AWSAccessKeyId>
<StringToSign>AWS4-HMAC-SHA256 20220712T203731Z 20220712/eu-west-2/s3/aws4_request 961d5d32676be187af1a7ccf8a92b8c29e2d851bdd51c46836aedce7cc9e089a</StringToSign>
<SignatureProvided>101e80ad27bfe4ed12a34b19fff4c17f87a3f639b92d62c8e7a79b13c876b1ca</SignatureProvided>
<StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 32 32 30 37 31 32 54 32 30 33 37 33 31 5a 0a 32 30 32 32 30 37 31 32 2f 65 75 2d 77 65 73 74 2d 32 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 39 36 31 64 35 64 33 32 36 37 36 62 65 31 38 37 61 66 31 61 37 63 63 66 38 61 39 32 62 38 63 32 39 65 32 64 38 35 31 62 64 64 35 31 63 34 36 38 33 36 61 65 64 63 65 37 63 63 39 65 30 38 39 61</StringToSignBytes>
<CanonicalRequest>GET /tmp/0344aa31-c756-49c3-8ce1-932ec23c895d X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=[REDACTED]/20220712/eu-west-2/s3/aws4_request&X-Amz-Date=20220712T203731Z&X-Amz-Expires=300&X-Amz-SignedHeaders=host;x-amz-acl&x-amz-acl=public-read host:[REDACTED].s3.eu-west-2.amazonaws.com x-amz-acl:public-read host;x-amz-acl UNSIGNED-PAYLOAD</CanonicalRequest>
<CanonicalRequestBytes>47 45 54 0a 2f 74 6d 70 2f 30 33 34 34 61 61 33 31 2d 63 37 35 36 2d 34 39 63 33 2d 38 63 65 31 2d 39 33 32 65 63 32 33 63 38 39 35 64 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 6f 6e 74 65 6e 74 2d 53 68 61 32 35 36 3d 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 34 58 4b 4a 50 55 57 34 55 43 42 4a 49 32 57 57 25 32 46 32 30 32 32 30 37 31 32 25 32 46 65 75 2d 77 65 73 74 2d 32 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 32 32 30 37 31 32 54 32 30 33 37 33 31 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 33 30 30 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 68 6f 73 74 25 33 42 78 2d 61 6d 7a 2d 61 63 6c 26 78 2d 61 6d 7a 2d 61 63 6c 3d 70 75 62 6c 69 63 2d 72 65 61 64 0a 68 6f 73 74 3a 73 68 61 64 6f 77 66 6f 75 6e 64 72 2d 75 70 6c 6f 61 64 73 2d 6c 6f 63 61 6c 2e 73 33 2e 65 75 2d 77 65 73 74 2d 32 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 78 2d 61 6d 7a 2d 61 63 6c 3a 70 75 62 6c 69 63 2d 72 65 61 64 0a 0a 68 6f 73 74 3b 78 2d 61 6d 7a 2d 61 63 6c 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes>
<RequestId>S6E8RFNVQ3WGAAHB</RequestId>
<HostId>yA998rWcqzfVIdD9HyrIJRJtbI/ge5opCEHEgpPoBBAuwRjgABub590OnA66JVHwyxHdo/a2uB6 ii/IxwZIGw==</HostId>
</Error>

Vue.js

@change=upload

convertFileNameToKebabCase(fileNameRaw) {
    let fileNameActual = _.kebabCase(fileNameRaw.split(".").shift());
    let fileExtension = fileNameRaw.split(".").pop();

    return `${fileNameActual}.${fileExtension}`;
  },
  async store(file, options = {}, fileAcl) {
      const response = await Vue.axios.post(
        "/vapor/signed-storage-url", {
          bucket: options.bucket || "",
          content_type: options.contentType || file.type,
          expires: options.expires || "",
          visibility: fileAcl || "",
          ignore_web_middleware: true
        }, {
          baseURL: options.baseURL || null,
          headers: options.headers || {}
        }
      );

      let headers = response.data.headers;

      if ("Host" in headers) {
        delete headers.Host;
      }

      if (typeof options.progress === "undefined") {
        options.progress = () => {};
      }

      // Reset axios instance as Amazon
      // does not like our Auth header

      const newInstance = axios.create();
      await newInstance.put(response.data.url, file, {
        headers: headers,
        onUploadProgress: progressEvent => {
          options.progress(
            progressEvent.loaded / progressEvent.total
          );
        }
      });

      response.data.extension = file.name.split(".").pop();

      return response.data;
    },
    async upload(event) {
      const {
        valid
      } = await this.$refs.provider.validate(event);

      if (valid) {
        this.reset();
        let fileData = this.$refs.file.files[0];

        this.fileName = fileData.name;
        this.url = false;

        try {
          const response = await this.store(
            this.$refs.file.files[0], {
              progress: progress => {
                this.uploadProgress = Math.round(progress * 100);
              }
            },
            "public-read"
          );

          Vue.axios
            .post("/file/commit", {
              uuid: response.uuid,
              key: response.key,
              bucket: response.bucket,
              name: this.convertFileNameToKebabCase(this.$refs.file.files[0].name),
              content_type: this.$refs.file.files[0].type
            })
            .then(success => {
              this.reset();
              this.url = success.data.data.file;
              this.uploadCompleted = true;
            })
            .catch(error => {
              this.reset();
              this.uploadFailed = true;
            });
        } catch (error) {
          this.reset();
          this.uploadFailed = true;
        }
      }
    },

CodePudding user response:

Three things to check:

  1. Region mismatch, the bucket is in region X but CLI/SDK goes to Region Y.
  2. A corruption or unusual setting in your AWS CLI profile, reset the profile, check if access key and secret are still valid.
  3. CORS configuration not containing <AllowedHeader>*</AllowedHeader>

Otherwise could you share some more details on the code that causes the error?

CodePudding user response:

I found the solution. I had to remove the following in the headers: x-amz-acl. I do not know why this was the problem but it seems to have worked. Hope if anyone comes across this in the future, try this solution.

if ("Host" in headers) {
   delete headers.Host;
   delete headers["x-amz-acl"];
}
  • Related