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;
示例数据:
- SecretAccessKey:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
- Content-MD5和内容类型:(可选-跳过)
- CanonicalizedAmzHeaders:(没有标头-已跳过)
- 资源:johnsmith.s3.amazonaws.com/photos/puppy.jpg
- CanonicalizedResource:/johnsmith/photes/pudge.jpg
提供了两个示例:
- 过期11175139620;签名:rucSbH0yNEcP9oM2XNlouVI3BH4%3D
- 过期11141889120;签名:vjbyPxybdZaNmGa%2ByT272YEAiv4%3D
要重新创建(CFHMAC从这里):
// 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))>
除了两种语言返回的$签名是:
- 过期11175139620;签名:NpgCjnDzrM%2BWZoENXmpNDUSSn8%3D
- 过期11141889120;签名:fScKGHCDI0NY5E7CYp9Vc8VKMbY%3D
我们一直很小心其他人提到的这些陷阱:
- hash_mac有第三个参数raw,必须将其设置为true
- S3伪码中字符串ToSign和密钥的顺序应该颠倒
- 整个字符串ToSign必须在一行上(以免创建额外的换行符)
编辑:根据Leigh的回答更新CF代码中的换行符;现在CF与PHP匹配。
我显然做错了什么,但不知道是什么
[我听说有人打趣说,亚马逊S3会被称为CSS——"复杂的存储服务",但这个名字已经取了!]
救命!
我能看到的两个问题
- 日期需要以特定方式格式化
- 您需要使用
LF
而不是文字"''n"
下面的结果与验证示例(即bWq2s1WEIj+Ydj0vQ697zp+IXMU=
)中的结果相匹配。注意:我从这里使用了hmacSHA1函数,但将其更改为getBytes("UTF-8)
代码:
<cfset newLine = chr(10)>
<cfset secretAccessKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY">
<cfset stringToSign = "GET#newLine##newLine##newLine#Tue, 27 Mar 2007 19:36:42 +0000#newLine#/johnsmith/photos/puppy.jpg">
<cfset signature = hmacSHA1(secretAccessKey, stringToSign)>
<cfset finalSignature = URLEncodedFormat(binaryEncode(signature, "base64"))>
<cfoutput>finalSignature = #finalSignature#</cfoutput>
****编辑1:**
有点可疑。那一页上的大多数例子都匹配。但是REST身份验证示例3:这里的查询字符串身份验证示例显示了生成签名vjbyPxybdZaNmGa%2ByT272YEAiv4%3D
的不同密钥和字符串。如果在CF中使用这些值,则会得到相同的签名。所以我想知道这是否只是一个文档错误?
<cfset secretAccessKey = "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV">
<cfset stringToSign = "GET#newLine##newLine##newLine#1141889120#newLine#/quotes/nelson">
**编辑2:
我确信REST示例是错误的。搜索结果显示此链接包含另一个示例键。如果在CF代码中替换它,签名就是您所期望的:rucSbH0yNEcP9oM2XNlouVI3BH4%3D
。
<cfset secretAccessKey = "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o">
<cfset stringToSign = "GET#newLine##newLine##newLine#1175139620#newLine#/johnsmith/photos/puppy.jpg">
这有帮助吗?
<cffunction name="getRequestSignature" access="private" output="false" returntype="string">
<cfargument name="verb" type="string" required="true" />
<cfargument name="bucket" type="string" required="true" />
<cfargument name="objectKey" type="string" required="true" />
<cfargument name="dateOrExpiration" type="string" required="true" />
<cfargument name="contentType" type="string" default="" />
<cfargument name="contentMd5" type="string" default="" />
<cfargument name="canonicalizedAmzHeaders" type="string" default=""
hint="A newline-delimited list of headers, in lexographical order, duplicates collapsed, and no extraneous whitespace. See Amazon's description of 'CanonicalizedAmzHeaders' for specifics." />
<cfscript>
var stringToSign = "";
var algo = "HmacSHA1";
var signingKey = "";
var mac = "";
var signature = "";
stringToSign = uCase(verb) & chr(10)
& contentMd5 & chr(10)
& contentType & chr(10)
& dateOrExpiration & chr(10)
& iif(len(canonicalizedAmzHeaders) GT 0, de(canonicalizedAmzHeaders & chr(10)), de(''))
& "/" & listAppend(bucket, objectKey, "/");
signingKey = createObject("java", "javax.crypto.spec.SecretKeySpec").init(variables.awsSecret.getBytes(), algo);
mac = createObject("java", "javax.crypto.Mac").getInstance(algo);
mac.init(signingKey);
signature = toBase64(mac.doFinal(stringToSign.getBytes()));
return signature;
</cfscript>
</cffunction>
完全从这里偷走了它:http://www.barneyb.com/barneyblog/projects/amazon-s3-cfc/
:)