使用Ruby生成的S3预签名URL上传时出现SignatureDoesNotMatch错误排查
S3预签名PUT URL上传文件遇SignatureDoesNotMatch错误排查方案
问题描述
使用Ruby生成AWS S3预签名PUT URL,通过Postman上传文件时返回SignatureDoesNotMatch错误,已确认accessKeyId、region、secretAccessKey、bucket_name参数均正确。
生成预签名URL的Ruby代码
def call(env) Aws.config.update({ region: '*region*', credentials: Aws::Credentials.new('*accessKeyId*', '*secretAccessKey*') }) key = "test/image.jpg" bucket_name = '*bucket_name*' signer = Aws::S3::Presigner.new(signature_version: 'v4') if key body = signer.presigned_url(:put_object, bucket: bucket_name, key: key) else body = "" end body end
已排查项
- 确认accessKeyId、region、secretAccessKey、bucket_name参数均正确
错误响应详情
响应头
HTTP/1.1 403 Forbidden x-amz-request-id: *request-id* x-amz-id-2: sSbb********************************************************************98= Content-Type: application/xml Transfer-Encoding: chunked Date: Mon, 21 Nov 2022 01:49:12 GMT Server: AmazonS3
响应体(XML)
<?xml version="1.0" encoding="UTF-8"?> <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>*Here is accessKeyId*</AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256 20221121T014413Z 20221121/ap-northeast-1/s3/aws4_request d1ffe599b69868e*********************************************25a3</StringToSign><SignatureProvided>4f51*********************************************db31f6******f735</SignatureProvided><StringToSignBytes>41 57 ...*Byte array follows here*</StringToSignBytes><CanonicalRequest>PUT /test/Receipt3.jpg X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=*Here is accessKeyId*%2F20221121%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20221121T014413Z&X-Amz-Expires=900&X-Amz-SignedHeaders=content-type%3Bhost&x-amz-acl=public-read content-type:image/jpeg host:*bucket name*.s3.ap-northeast-1.amazonaws.com content-type;host UNSIGNED-PAYLOAD</CanonicalRequest><CanonicalRequestBytes>50 55 ...*Byte array follows here*</CanonicalRequestBytes><RequestId>*request-id*</RequestId><HostId>sSbbjrOYs9d4aAf************GSIvc************CSJhGPR************98=</HostId></Error>
排查步骤
- 检查文件路径(Key)一致性:从响应的
CanonicalRequest可见,实际请求的Key是/test/Receipt3.jpg,但代码中生成预签名URL时指定的Key是test/image.jpg,两者完全不匹配。签名基于生成URL时的Key计算,实际上传用不同Key必然导致签名验证失败,需确保Postman上传时使用的Key和预签名生成时的Key完全一致。 - 检查请求头匹配性:预签名URL的
X-Amz-SignedHeaders指定了content-type;host,但响应的CanonicalRequest中出现了x-amz-acl=public-read参数,说明Postman请求中添加了x-amz-acl头,但生成预签名URL时未包含该参数。S3要求所有请求头必须在预签名时声明,否则会导致签名不匹配。要么在生成预签名URL时添加acl: 'public-read'参数,要么删除Postman中的x-amz-acl请求头。 - 验证时间同步:预签名URL默认有效期900秒,若本地机器时间与AWS服务器时间偏差超过15分钟,会触发签名验证失败,检查Postman所在设备的系统时间是否准确。
- 确认URL未被篡改:复制预签名URL时确保没有误修改参数(如
X-Amz-Date、X-Amz-Credential等),任何手动修改都会导致签名失效。 - 检查S3端点正确性:确认region对应的S3端点与请求的Host一致,响应中Host为
*bucket name*.s3.ap-northeast-1.amazonaws.com,需确保代码中指定的region确实是ap-northeast-1。
内容的提问来源于stack exchange,提问作者Naoto Omori
相关产品推荐
相关产品推荐

