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;
Примеры данных:
Предоставляются два примера:
Чтобы воссоздать это (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))>
ЗА ИСКЛЮЧЕНИЕМ, что $ подпись, возвращаемая обоими языками:
Мы были осторожны с этими пропастями, о которых говорили другие:
EDIT: Обновлены новые строки в CF-коде, основанные на ответе Ли; теперь CF соответствует PHP.
Я, очевидно, что-то делаю неправильно, но не могу понять, что.
[Я слышал, что он сказал, что Amazon 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 Authentication Example 3: Query String Authentication Пример здесь показывает другой ключ и строку, которые создают подпись 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/
🙂