Amazon 始终生成与 PHP 或 CF 不同的哈希,这会导致持续的“SignatureDoesNotMatch”错误。
根据文档,GET 请求 [没有 REST 标头] 的签名如下:
Signature = URL-Encode( Base64( HMAC-SHA1( SecretAccessKey, UTF-8-Encoding-Of( StringToSign ) ) ) );
StringToSign = HTTP-VERB + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Expires + "\n" +
CanonicalizedAmzHeaders +
CanonicalizedResource;
示例数据:
- 秘密访问密钥:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
- Content-MD5 和 Content-Type:(可选 - 跳过)
- CanonicalizedAmzHeaders:(无标题 - 跳过)
- 资源:johnsmith.s3.amazonaws.com/photos/puppy.jpg
- 规范化资源:/johnsmith/photos/puppy.jpg
提供了两个示例:
- 过期1175139620 ; 签名:rucSbH0yNEcP9oM2XNlouVI3BH4%3D
- 过期1141889120 ; 签名:vjbyPxybdZaNmGa%2ByT272YEAiv4%3D
要重新创建这个(CFHMAC from here):
// PHP
$expires = 1175139620;
$SecretAccessKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
$StringToSign = "GET\n\n\n$expires\n/johnsmith/photos/puppy.jpg";
$signature = urlencode( base64_encode( hash_hmac('sha1', utf8_encode($StringToSign), $SecretAccessKey, true)));
// ColdFusion
<cfset LF = chr(10)>
<cfset expires = 1141889120>
<cfset SecretAccessKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY">
<cfset StringToSign = "GET#LF##LF##LF##expires##LF#/johnsmith/photos/puppy.jpg">
<cfset signature = URLEncodedFormat( CFHMAC(StringToSign, SecretAccessKey))>
除了两种语言返回的 $signature 是:
- 过期1175139620 ; 签名:NpgCjnDzrM%2BWFzoENXmpNDUsSn8%3D
- 过期1141889120 ; 签名:fScKGHCDI0NY5E7CYp9Vc8VKMbY%3D
我们一直小心其他人提到的这些陷阱:
- hash_mac 有第三个参数 raw,它必须设置为 true。
- S3 伪代码中 stringToSign 和 key 的顺序应该颠倒。
- 整个 stringToSign 必须在一行上(以免创建额外的换行符)。
编辑:根据 Leigh 的回答更新了 CF 代码中的换行符;现在 CF 匹配 PHP。
我显然做错了什么,但不知道是什么。
[我听说 Amazon S3 会被称为 CSS——“复杂的存储服务”,但这个名字已经被人使用了!]
请帮忙!