49315


現在webサービスのフォーム値をawsのs3に保存しようとしているのですが，v2認証がうまくいきません．

awsの[ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/RESTAuthentication.html)では以下の手順で署名を作成するように記述されています．

[code]

    Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;
    
    Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) );
    
    StringToSign = HTTP-Verb + "\n" +
        Content-MD5 + "\n" +
        Content-Type + "\n" +
        Date + "\n" +
        CanonicalizedAmzHeaders +
        CanonicalizedResource;
    
    CanonicalizedResource = [ "/" + Bucket ] +
        <HTTP-Request-URI, from the protocol name up to the query string> +
        [ subresource, if present. For example "?acl", "?location", "?logging", or "?torrent"];
    
    CanonicalizedAmzHeaders = <described below>
    
[/code]

そして同ページで以下のようなサンプルがかかれています．

[code]

    -----------------request--------------------------------
    GET /photos/puppy.jpg HTTP/1.1
    Host: johnsmith.s3.amazonaws.com
    Date: Tue, 27 Mar 2007 19:36:42 +0000
    
    Authorization: AWS AKIAIOSFODNN7EXAMPLE:
    bWq2s1WEIj+Ydj0vQ697zp+IXMU=
    
    --------------------stringToSign-----------------------
    GET\n
    \n
    \n
    Tue, 27 Mar 2007 19:36:42 +0000\n
    /johnsmith/photos/puppy.jpg
    
[/code]

これらのサンプルを元に署名処理を書きました．  
具体的には以下のようにかきました．

[code]

    ```
    var accessKey = 'AKIAIOSFODNN7EXAMPLE'
    var secretKey = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
    var stringToSign = `
    GET\n
    \n
    \n
    Tue, 27 Mar 2007 19:36:42 +0000\n
    /johnsmith/photos/puppy.jpg
    `
    //UTF-8-Encoding-Of( StringToSign )
    var enStringToSign = encodeURI(stringToSign);
    //HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign )
    var hmacSha1 = CryptoJS.HmacSHA1(secretKey, enStringToSign);
    //Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) );
    var signature = CryptoJS.enc.Base64.stringify(hmacSha1);
    var authorization = `AWS ${accessKey}:${signature}`;
    console.log(authorization)
    //"AWS AKIAIOSFODNN7EXAMPLE:KXQrJvmB8Mr4qb6x5wVxcgEdBM8="
    ```
    
[/code]

sample通り

[code]

    ```
    AWS AKIAIOSFODNN7EXAMPLE:
    bWq2s1WEIj+Ydj0vQ697zp+IXMU=
    ```
    
[/code]

と出力されません．  
どこが悪いかわかる方教えていただけると助かります

## 環境

  * os  
windows

  * 言語  
javascript

  * ライブラリ  
[crypto.js](https://github.com/brix/crypto-js)


CC BY-SA 4.0
2018-10-15T11:49:33.450
49303
2018-10-15T14:40:53.510
question
javascript aws amazon-s3
awsのREST リクエストの署名(verstion 2)と認証について


まず明らかにおかしいのは、この擬似コードを:

[code]

    StringToSign = HTTP-Verb + "\n" +
        Content-MD5 + "\n" +
        Content-Type + "\n" +
        Date + "\n" +
        CanonicalizedAmzHeaders +
        CanonicalizedResource;
    
[/code]

こうなおしてしまっているところです。

[code]

    var stringToSign = `
    GET\n
    \n
    \n
    Tue, 27 Mar 2007 19:36:42 +0000\n
    /johnsmith/photos/puppy.jpg
    `
    
[/code]

JavaScriptのバッククオート(Template
literal)は、ソースコード上の全ての改行を(`\n`にして)保持するので、上記のコードではあちこちに余分な改行が入ってしまいます。例えば以下のようにする必要があるでしょう。

[code]

    var stringToSign = `GET
    
    
    Tue, 27 Mar 2007 19:36:42 +0000
    /johnsmith/photos/puppy.jpg`
    
[/code]

また、あなたのこの行:

[code]

    var enStringToSign = encodeURI(stringToSign);
    
[/code]

これに相当する行は、擬似コードのどこにもありません。`UTF-8-Encoding-Of( StringToSign
)`をどうするのか迷われたのでしょうが、この擬似コードは文字列をUTF-8表現のバイト列に変換することを表していて、その処理はCryptoJSに文字列を渡すことで自動的にやってくれます。

で、最後の1個がここ。

[code]

    var hmacSha1 = CryptoJS.HmacSHA1(secretKey, enStringToSign);
    
[/code]

秘密鍵と変換対象のメッセージが逆転しています。つい擬似コードの`HMAC-SHA1( YourSecretAccessKeyID,
UTF-8-Encoding-Of( StringToSign ) )`の順番にひきずられたのでしょうが、正しくはこちら。

[code]

    var hmacSha1 = CryptoJS.HmacSHA1(stringToSign, secretKey);
    
[/code]

(上記したように`enStringToSign`は要らないので`stringToSign`に変えてあります。)

* * *

全部つなげると、こんな感じでしょうか。

[code]

    var accessKey = 'AKIAIOSFODNN7EXAMPLE';
    var secretKey = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY';
    var stringToSign = `GET
    
    
    Tue, 27 Mar 2007 19:36:42 +0000
    /johnsmith/photos/puppy.jpg`;
    //HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign )
    var hmacSha1 = CryptoJS.HmacSHA1(stringToSign, secretKey);
    //Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) );
    var signature = CryptoJS.enc.Base64.stringify(hmacSha1);
    var authorization = `AWS ${accessKey}:${signature}`;
    console.log(authorization)
    
[/code]

お試しに際は、一文字でも間違えると同じ結果になりませんので、ご注意ください。


CC BY-SA 4.0
2018-10-15T14:40:53.510
49315
2018-10-15T14:40:53.510
13972
49303
answer