JMeter 在将文件上传到 s3 时抛出错误“签名不匹配”

JMeter throws error 'Signature doesn't match' while uploading file to s3

谁能帮我弄清楚发生了什么事?

我正在尝试对用户可以上传和下载文件的应用程序进行负载测试。

旅程:

第 1 步:当用户从磁盘中选择一个文件(POST 请求)时,它会创建一个文件 ID 和带有 uuid 的路径。

响应如下: {"id":"FILE-VX-1234","path":"uuid/filename.jpg","uri":["s3://{location}/{uuid}/{filename}?endpoint=s3.dualstack.eu-west-1.amazonaws.com"],"state":"OPEN","size":-1,"timestamp":"2020-02-13T10:59:43.146+0000","refreshFlag":1,"storage":"STORAGEID","metadata":{}

第 2 步:使用这些(POST 请求)以带有 assesskeyID、secretaccesskey 和 sessionToken 的 s3 uri 响应。

响应如下: {"uri":["s3://{accesskeyID}:{secretaccesskey}@{storage location}/{uuid}/{filename}?endpoint=s3.dualstack.eu-west-1.amazonaws.com&sessionToken={security token}"]}

第 3 步:使用这些和添加的临时参数(日期),PUT 请求上传 s3 存储桶中的文件。

Header 看起来像:

Accept: */*

Accept-Encoding: gzip, deflate, br

Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

Authorization: AWS4-HMAC-SHA256 Credential=${accesskeyID}/${currentDate}/{region}/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=${secretaccesskey}

Connection: keep-alive

Content-Length: 145541

Content-Type: image/jpeg

Host: <the host address>

Origin: https://{url}

Referer: https://{url}/upload/

Sec-Fetch-Mode: cors

Sec-Fetch-Site: cross-site

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36

X-Amz-Content-Sha256: UNSIGNED-PAYLOAD

X-Amz-Date:${currentDateInUTC}

x-amz-security-token: ${sessionToken}

X-Amz-User-Agent: aws-sdk-js/2.409.0 callback

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

我已验证PUT请求中传递的signature(secretaccesskey)、accesskeyID和sessionToken是正确的。

注:附加参数date and "{region}/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date; x-amz-security-token;x-amz-user-agent" 中的授权错误是硬编码的。

如果不了解您如何为请求生成签名,就不可能提供任何帮助,即 Authorization header

根据 Signing and Authenticating REST Requests 文章

The Amazon S3 REST API uses a custom HTTP scheme based on a keyed-HMAC (Hash Message Authentication Code) for authentication. To authenticate a request, you first concatenate selected elements of the request to form a string. You then use your AWS secret access key to calculate the HMAC of that string. Informally, we call this process "signing the request," and we call the output of the HMAC algorithm the signature, because it simulates the security properties of a real signature. Finally, you add this signature as a parameter of the request by using the syntax described in this section.

这里有一个 pseudo-code 演示如何生成 header:

Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;

Signature = Base64( HMAC-SHA1( YourSecretAccessKey, UTF-8-Encoding-Of( StringToSign ) ) );

StringToSign = HTTP-Verb + "\n" +
    Content-MD5 + "\n" +
    Content-Type + "\n" +
    Date + "\n" +
    CanonicalizedAmzHeaders +
    CanonicalizedResource;

CanonicalizedResource = [ "/" + Bucket ] +
    <HTTP-Request-URI, from the protocol name up to the query string> +
    [ subresource, if present. For example "?acl", "?location", "?logging", or "?torrent"];

CanonicalizedAmzHeaders = <described below>

您可以查看 How to Handle Dynamic AWS SigV4 in JMeter for API Testing 文章中的示例实现。