1

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

提供了两个示例:

  1. 过期1175139620 ; 签名:rucSbH0yNEcP9oM2XNlouVI3BH4%3D
  2. 过期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 是:

  1. 过期1175139620 ; 签名:NpgCjnDzrM%2BWFzoENXmpNDUsSn8%3D
  2. 过期1141889120 ; 签名:fScKGHCDI0NY5E7CYp9Vc8VKMbY%3D

我们一直小心其他人提到的这些陷阱:

  1. hash_mac 有第三个参数 raw,它必须设置为 true。
  2. S3 伪代码中 stringToSign 和 key 的顺序应该颠倒。
  3. 整个 stringToSign 必须在一行上(以免创建额外的换行符)。

编辑:根据 Leigh 的回答更新了 CF 代码中的换行符;现在 CF 匹配 PHP。

我显然做错了什么,但不知道是什么。
[我听说 Amazon S3 会被称为 CSS——“复杂的存储服务”,但这个名字已经被人使用了!]

请帮忙!

4

2 回答 2

0

这会有帮助吗?

<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/

:)

于 2012-08-22T20:47:39.850 回答
0

(也可以发布这个,因为我已经写好了.. :)

我可以看到两个问题

  1. 日期需要以特定方式格式化
  2. 您需要使用 aLF而不是文字 "\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 Authentication Example 3: Query String Authentication Example 这里显示了一个不同的密钥和字符串来产生签名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">
于 2012-08-22T20:58:41.060 回答