aws-sdk-go-v2
aws-sdk-go-v2 copied to clipboard
"SignatureDoesNotMatch" Error When Using PresignPutObject with Expires
Describe the bug
When generating a presigned URL with PresignPutObject and setting the Expires field, attempting to put an object to S3 returns the error "SignatureDoesNotMatch". However, without setting the Expires field, it works fine.
Expected Behavior
return 200
Current Behavior
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
Reproduction Steps
// not working
request, err := s.s3Presign.PresignPutObject(ctx, &s3.PutObjectInput{
Bucket: &bucket,
Key: &key,
Expires: &expire,
}, s3.WithPresignExpires(6*time.Hour))
if err != nil {
return nil, err
}
// works fine
request, err := s.s3Presign.PresignPutObject(ctx, &s3.PutObjectInput{
Bucket: &bucket,
Key: &key,
}, s3.WithPresignExpires(6*time.Hour))
if err != nil {
return nil, err
}
Possible Solution
No response
Additional Information/Context
No response
AWS Go SDK V2 Module Versions Used
Compiler and Version used
go version go1.21.3 darwin/arm64
Operating System and version
macOS Ventura 13.6.4
Hi @xuanyu66,
Thanks for reaching out.
There is a distinction between the expires field you set on a putObject request which controls how long an object is cacheable, and the x-amz-expires query parameter set by SDK which controls the validity of a presigned URL.
For example, using the functional options will result in an x-amz-expires header, being hoisted into the query string.
presignObject, err := presigner.PresignPutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String("testbucket"),
Key: aws.String("sample.txt"),
Body: data,
}, func(options *s3.PresignOptions) {
options.Expires = 30 * time.Minute
})
https://testbucket.s3.us-east-1.amazonaws.com/sample.txt?
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=REDACTED/20240302/us-east-1/s3/aws4_request&
X-Amz-Date=20240302T042717Z&
X-Amz-Expires=1800&
X-Amz-SignedHeaders=content-length;content-type;host&
x-id=PutObject&
X-Amz-Signature=REDACTED
When you set the expires request parameter on PutObject, the presigned request will calculate the signature as if an expires header is present at the time of making the request.
presignObject, err := presigner.PresignPutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String("testbucket"),
Key: aws.String("sample.txt"),
Body: data,
Expires: aws.Time(time.Now().Add(30 * time.Minute)),
}, func(options *s3.PresignOptions) {
options.Expires = 30 * time.Minute
})
https://testbucket.s3.us-east-1.amazonaws.com/sample.txt?
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=REDACTED/20240302/us-east-1/s3/aws4_request&
X-Amz-Date=20240302T042932Z&
X-Amz-Expires=1800&
X-Amz-SignedHeaders=content-length;content-type;expires;host&
x-id=PutObject&
X-Amz-Signature=REDACTED
In the latter generated presigned URL you can see that expires is listed under the X-Amz-SignedHeaders parameter, which means that when you make a request to this presigned URL, youll have to add that header and the correct value to the request for the signature to match.
Thanks, Ran~
So, I need to add a header such as "Expires: Sat, 27 Jun 2015 23:59:59 GMT"?
@RanVakninI have already add this header, but the error still exists
And I also tried with the host header.
@xuanyu66 The return of the PresignPutObject includes a set of http.Headers that need to be passed on the request for it to work.
This is not at all ideal, but is a necessity with S3 due to it not fully supporting query hoisting across various request parameters. We maintain a list of these inputs internally that we know (or knew in the past) to not work in the query, Expires is one of them.