署名リクエスト


Private Keyで署名して、Amazon PayへのすべてのAPIリクエストを保護する必要があります。署名は、リクエスト者のIDを確認し、転送中にデータを保護するために使用されます。次の手順でリクエストに署名します。

ステップ1:正規のリクエストを生成する
リクエストの内容 (host, action, headers, etc.) を標準(正規)形式に成形します。

ステップ2:署名する為の文字列(StringToSign)を作成する
ハッシュアルゴリズムの指定(AMZN-PAY-RSASSA-PSS)と正規リクエストのダイジェスト(ハッシュ)を連結して、署名する為の文字列を作成します。

ステップ3:署名を計算する
SHA256ハッシュを使用したRSASSA-PSSアルゴリズムを使用して署名する文字列(StringToSign)に署名し、Base64で結果をエンコードします。

ステップ4:HTTPリクエストに署名を追加する

署名を計算したら、それをリクエストヘッダーとして追加します。

ステップ1. 正規のリクエストを生成します

標準化された(正規の)形式でリクエストからの情報を含む文字列を作成します。

正規リクエストの擬似コードの例:

CanonicalRequest =
  HTTPRequestMethod + '\n' +
  CanonicalURI + '\n' +
  CanonicalQueryString + '\n' +
  CanonicalHeaders + '\n' +
  SignedHeaders + '\n' +
  HexEncode(Hash(Payload))

リクエストの例:

POST 
/live/v2/checkoutSessions

accept:application/json 
content-type:application/json 
x-amz-pay-date:20190923T231908Z 
x-amz-pay-host:pay-api.amazon.com 
x-amz-pay-idempotency-key:cllHyiNvS8cJ8Zas 
x-amz-pay-region:us 

accept;content-type;x-amz-pay-date;x-amz-pay-host;x-amz-pay-idempotency-key;x-amz-pay-region 
0b6c19dc5bc1883ebd68d3c77ee929922c6b4a59e0a506d96c45e0c024c3295b

正規のリクエストを作成するには、各ステップの次のコンポーネントを1つの文字列に連結します。

1. HTTPリクエストメソッド(GET, PUT, POST, etc.)で開始し、その後に改行文字を続けます。

2. 正規URIを追加し、その後に改行文字を追加します。正規URIは、HTTPホストからクエリ文字列パラメータ(存在する場合)の前の疑問符文字( "?")までのURI内のすべてです。 RFC 3986に従ってURIパスを正規化します。冗長パスコンポーネントと相対パスコンポーネントを削除します。各パスセグメントはURIエンコードする必要があります。

3. 正規のクエリ文字列を追加し、その後に改行文字を追加します。リクエストにクエリ文字列が含まれていない場合は、空の文字列(基本的には空白行)を使用します。正規のクエリ文字列を作成するには以下のとおりです。

  1. パラメータ名を文字コードポイントで昇順に並べ替えます。たとえば、大文字のFで始まるパラメータ名は、小文字のbで始まるパラメータ名の前にあります。
  2. 次のルールに従って、各パラメータの名前と値をURIエンコードします。
    • RFC 3986 定義で予約予約されていない文字(A-Z, a-z, 0-9, ハイフン ( - ), アンダースコア ( _ ), ピリオド ( . ), チルダ ( ~ ))はURIエンコードしないでください。
    • 他のすべての文字を%XYでパーセントエンコードします。ここで、XとYは16進文字(0-9および大文字のA-F)です。たとえば、スペース文字は%20としてエンコードする必要があり(一部のエンコードスキームでは使用されていないので'+'は使用しないでください)、拡張UTF-8文字は%XY%ZA%BCの形式である必要があります。
  3. ソートされたリストの最初のパラメータ名から始めて、正規のクエリ文字列を作成します。
  4. パラメータごとに、URIエンコードされたパラメータ名、等号文字(=)、URIエンコードされたパラメータ値を追加します。値のないパラメータには空の文字列を使用します。
  5. リストの最後の値を除いて、各パラメータ値の後にアンパサンド文字(&)を追加します。

4. 正規ヘッダーを追加し、その後に改行文字を追加します。正規ヘッダーは、署名されたリクエストに含めるすべてのHTTPヘッダーのリストです。必須となるAPIの概要 をご覧ください。以下のとおり正規ヘッダーリストを作成します。

  1. すべてのヘッダー値を小文字に変換し、先頭のスペースと末尾のスペースを削除し、ヘッダー値の連続するスペースを単一のスペースに変換します。
  2. ヘッダーを文字コードで並べ替える
  3. ヘッダー名を繰り返し処理し、次のルールを使用して各ヘッダーエントリを作成します。
    • 小文字のヘッダー名の後にコロンを追加します。
    • ヘッダーの値のコンマ区切りリストを追加します。
    • 複数の値を持つヘッダーの値を並べ替えないでください。新しい行として追加します( '\ n')。

ヘッダーの正規リストを作成するための擬似コード:

CanonicalHeadersEntry0 = Lowercase(HeaderName) + ':' + Trim(HeaderValue) + '\n'
CanonicalHeaders = CanonicalHeadersEntry0 + CanonicalHeadersEntry1 + ... + CanonicalHeadersEntryN

(Lowercaseは、すべての文字を小文字に変換する関数を表します。 Trimは、値の前後の余分な空白を削除し、連続するスペースを単一のスペースに変換します。)

5. 署名されたヘッダーを追加し、その後に改行文字を追加します。この値は、正規ヘッダーに含めたヘッダーのリストです。

6. SHA256を使用して、HTTPSリクエスト本文のハッシュを作成します。ハッシュされたペイロードは、小文字の16進文字列として表す必要があります。

7. 各ステップのコンポーネントを単一の文字列に結合して、完成した正規リクエストを作成します。最後のコンポーネントを除く各コンポーネントは、改行文字で終わることに注意してください。

ステップ2. 署名する文字列を作成します

署名する文字列の擬似コード構造:

StringToSign =
    Algorithm + '\n' +
    LowerCase(Hex(Hash(CanonicalRequest)))

署名する文字列の例:

AMZN-PAY-RSASSA-PSS 
c5c55b2d523738b72c0b96f6d5e0d712d9496573490125b191eeb6840c052ffb

署名する文字列を作成するには、アルゴリズムと正規リクエストのダイジェストを連結します。

1. アルゴリズムの指定から始めて、改行文字を続けます。この値は、正規リクエストのダイジェストを計算するために使用するハッシュアルゴリズムです。

AMZN-PAY-RSASSA-PSS 

2. 前の手順で作成した正規リクエストのSHA256ハッシュを追加します。この値の後に改行文字は続きません。ハッシュ化された正規要求は、RFC 4648のセクション8で定義されているように、16進数でエンコードされている必要があります。

f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59

ステップ3. 署名を計算します

署名を計算するには、ステップ2で作成した署名する文字列に秘密鍵を使用して署名します。 SHA256ハッシュとソルト長20のRSASSA-PSSアルゴリズムを使用します。結果をBase64エンコードして、この手順を完了します。 RSASSA-PSSを使用して計算されたすべての署名は、入力が同じであっても一意であることに注意してください。

署名を計算するための擬似コード:

signature = RSASSA-PSS(privateKey, StringToSign); 
base64_encoded_signature = Base64Encode(signature);

計算された署名の例:

o/THnkmKYB+jCPOo3Qchux3T/dKmOqLTiL2MMmfshGIgATo3206BlJVjAIqL8LhuEu9c70conBoMsfc5ZWvdijTQ893fIXA7WjEKFqTwyBOQz2EIjep7f8Yf4g5bgWzKLJYK3ABTptoND96yjo3IZVTQLHW+G2FQs8X/lSW8XUjHgobcSUKF4X2/3ukZQ+QEtw5vLZcpzcvyhdwBZakgqcXQRuaryS3iekZXUsdajOd+pMMSOw5yQXLE3qXukxiWXNcDnc3bCw+8JtynfcVYUX+Q3Z6/J0p9nODmfNAuvhTgpfnFpXKRUTGuhANiOyOSN8orWSx1MVPPwHSyZhhpPA==

ステップ4. HTTPリクエストに署名を追加します

署名を計算したら、次の形式でAuthorizationという名前のHTTPヘッダーとしてリクエストに追加します: Algorithm + PublicKeyId + SignedHeaders + Signature

  • アルゴリズムは常にAMZN-PAY-RSASSA-PSSになります
  • Public Key Idは、Amazon Payによって提供される認証情報です。詳細については、 Public Key Idを取得する を参照してください。
  • SignedHeaderは、署名に含まれるすべてのヘッダーのリストです。 Authorizationヘッダーを署名付きヘッダーのリストに含めないでください。
  • 署名は、ステップ3で計算された値です。

ヘッダーを作成するための擬似コード:

Authorization: algorithm PublicKeyId=publicKeyId, SignedHeaders=accept;content-type;x-amz-pay-date;x-amz-pay-host;x-amz-pay-idempotency-key;x-amz-pay-region, Signature=base64_encoded_signature

終了した承認ヘッダーの例:

Authorization: AMZN-PAY-RSASSA-PSS PublicKeyId=AHEGSJCM3L2S637RBGABLAFW, SignedHeaders=accept;content-type;x-amz-pay-date;x-amz-pay-host;x-amz-pay-idempotency-key;x-amz-pay-region, Signature=o/THnkmKYB+jCPOo3Qchux3T/dKmOqLTiL2MMmfshGIgATo3206BlJVjAIqL8LhuEu9c70conBoMsfc5ZWvdijTQ893fIXA7WjEKFqTwyBOQz2EIjep7f8Yf4g5bgWzKLJYK3ABTptoND96yjo3IZVTQLHW+G2FQs8X/lSW8XUjHgobcSUKF4X2/3ukZQ+QEtw5vLZcpzcvyhdwBZakgqcXQRuaryS3iekZXUsdajOd+pMMSOw5yQXLE3qXukxiWXNcDnc3bCw+8JtynfcVYUX+Q3Z6/J0p9nODmfNAuvhTgpfnFpXKRUTGuhANiOyOSN8orWSx1MVPPwHSyZhhpPA==

無効な署名のトラブルシューティング

署名が無効な場合、InvalidRequestSignatureエラーレスポンスが返されます。

{
    "reasonCode":"InvalidRequestSignature",
    "message":"Unable to verify signature", 
    "signing String" : "[AMZN-PAY-RSASSA-PSS\n3e212aa879befa01ecce1278e96a252cd0c98ac9e663e898b879ebd8d46eae2f]",
    "signature" : "[some_signature]"
}

以下は、よくあるミスとその修正方法の説明です。

  • 「署名する文字列(string to sign)」の不一致 - 署名された文字列は、APIが期待していた文字列と同じではありませんでした。 エラーメッセージには、APIが署名の生成に期待していた署名文字列が含まれます ( ステップ2. 署名する文字列を作成します)を参照。ステップ2で計算した文字列がAPIエラーの文字列と一致することを確認します。

  • リクエストのエンコードが正しくありません。 Amazon Pay APIは、UTF-8エンコーディングを想定しています。別の方法を使用してリクエストをエンコードしていないことを確認してください。

  • ソルトの長さが正しくありません。 署名アルゴリズムのソルト長は20でなければなりません。

  • 日付値に一貫性がありません。 x-amz-pay-date headerは、署名の生成に使用された日付と一致する必要があります。リクエスト全体に同じ日付を使用していることを確認してください。