使用aws-sdk-php生成S3预签名URL遇SignatureDoesNotMatch错误的解决方法
AWS S3预签名URL签名不匹配问题排查与解决
问题场景
生成AWS S3预签名URL用于浏览器下载文件时,持续收到SignatureDoesNotMatch错误,错误详情如下:
<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>xxxxxxxxxx</AWSAccessKeyId> <StringToSign>AWS4-HMAC-SHA256 20230729T002138Z 20230729/us-west-1/s3/aws4_request faxxxxxxxxxxxeb2a</StringToSign> <SignatureProvided>c6d5xxxxxxxxx3df9</SignatureProvided> <StringToSignBytes>41 57 53 34 2d 35 65 62 32 61 66 35 66 66 30 64</StringToSignBytes> <CanonicalRequest>GET //dummy.pdf X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIXX%2F729%2Fus-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230729T002138Z&X-Amz-Expires=1200&X-Amz-SignedHeaders=host host:test-storage.s3.us-west-1.amazonaws.com host UNSIGNED-PAYLOAD</CanonicalRequest> <CanonicalRequestBytes>47 45 54 55 4e 53 49 47 4e 53 49 47 4e 55 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes> <RequestId>EMXXXXXX032</RequestId> <HostId>FcXXXXXXXXo=</HostId> </Error>
使用的PHP代码如下:
$client = new S3Client([ 'version' => 'latest', 'region' => 'us-west-1', 'credentials' => [ 'key' => 'xxxxxxx', 'secret' => 'xxxxxxx', ], ]); $cmd = $client->getCommand('GetObject', [ 'Bucket' => 'test-storage', 'Key' => 'dummy.pdf', ]); $tmp = $client->createPresignedRequest($cmd, '+20 minutes'); $presignedUrl = (string) $tmp->getUri();
生成的预签名URL示例:
https://test-storage.s3.us-west-1.amazonaws.com/dummy.pdf?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKI0729%2Fus-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230729T004906Z&X-Amz-SignedHeaders=host&X-Amz-Expires=1200&X-Amz-Signature=11111111534793c314b
错误原因分析
从错误返回的CanonicalRequest可定位核心问题:
- 路径格式错误:请求路径为
//dummy.pdf,正确格式应为/dummy.pdf,双斜杠会导致签名计算逻辑偏差。 - Credential参数截断:
X-Amz-Credential中的日期部分仅为729,AWS签名要求日期为完整YYYYMMDD格式(如20230729),截断会直接导致签名验证失败。 - SignedHeaders格式混乱:
CanonicalRequest中重复出现host字段,不符合AWS签名规范,破坏了签名计算的一致性。 - SDK版本兼容性:使用
latest作为SDK版本可能引入未预期的逻辑异常,导致签名生成流程出错。
解决方法
指定明确的SDK稳定版本
将S3Client配置中的version从latest替换为AWS S3的标准稳定版本2006-03-01,避免版本兼容问题:$client = new S3Client([ 'version' => '2006-03-01', 'region' => 'us-west-1', 'credentials' => [ 'key' => 'your-access-key', 'secret' => 'your-secret-key', ], ]);验证AWS凭证有效性
确认访问密钥(key和secret)无拼写错误、无多余空格,且该密钥拥有目标S3对象的s3:GetObject权限。检查生成URL的参数格式
生成预签名URL后,手动验证:X-Amz-Credential中的日期为完整YYYYMMDD格式- 请求路径为单斜杠开头(如
/dummy.pdf) X-Amz-SignedHeaders仅包含必要字段(如host),无重复内容
清理环境缓存
若使用环境变量或缓存存储凭证,清理缓存并确认环境变量中的凭证值正确。
内容的提问来源于stack exchange,提问作者MalcolmInTheCenter
相关产品推荐
相关产品推荐

