1

node.js で Simple Pay ボタン フォームに署名するための Amazon の指示に従うために、過去 6 時間を費やしました。署名を受け入れることができず、紛らわしい指示のすべての順列を試しました。誰かが私の悲惨さから私を助けることができますか?

私が得るエラーは

入力パラメーターの署名が無効です

これが私の手順です

var params={
    "returnUrl": "[confidential]",
    "ipnUrl": "[confidential]",
    "processImmediate": "1",
    "accessKey" :"[AWS key]",
    "collectShippingAddress" :"0",
    "isDonationWidget" :"0",
    "amazonPaymentsAccountId" :"[the button generator creates this but there is no mention in the docs]",
    "referenceId" :ref,
    "cobrandingStyle" :"logo",
    "immediateReturn" :"1",
    "amount" :"USD "+amount,
    "description" : desc,
    "abandonUrl" :"[confidential]",
    "signatureMethod": "HmacSHA256", //docs not clear if signatureMethod and signatureVersion should be included, but I've tried all permutations and can't get it to work
    "signatureVersion" :"2"
    }
        //Docs say it should confirm to     
    /*
    StringToSign = HTTPVerb + "\n" +
    ValueOfHostHeaderInLowercase + "\n" +
    HTTPRequestURI + "\n" +         
    CanonicalizedQueryString <from the preceding step>
   */
    //sort parameters (natural byte order)
    var p=_.pairs(params);
    var psorted=_.sortBy(p, function(p) { return p[0];});
    //start to construct the form
    var input='';
    for(var i=0; i<psorted.length;i++) {
        input+="<input type='hidden' name='"+psorted[i][0]+"' value='"+psorted[i][1]+"'>";
    }
    //prepare the string to be signed
    var qstring='POST'+'\n';
    qstring+='https://authorize.payments.amazon.com'+'\n';
    qstring+='/pba/paypipeline'+'\n';
    for(var i=0; i<psorted.length;i++) {
        psorted[i][0]=encodeURI(psorted[i][0]);
        psorted[i][1]=encodeURI(psorted[i][1]);
        qstring+=psorted[i][0]+'='+psorted[i][1];
        if (i<psorted.length-1) {qstring+='&';} 
    };

    console.log(qstring+'\n\n');
    var sig=crypto.createHmac("SHA256", "[AWS Secret Key") 6
        .update(qstring)
        .digest('base64');
    input+="<input type='hidden' name='signature' value='"+sig+"'>"; //doesn't matter whether or not i url encode this
    console.log(input);

パラメータを次のように変換します

POST
authorize.payments.amazon.com
/pba/paypipeline
abandonUrl=XXXX&accessKey=XXXXX&amazonPaymentsAccountId=XXXXXX&amount=USD%203&cobrandingStyle=logo&collectShippingAddress=0&description=sadasdd&immediateReturn=1&ipnUrl=XXXXXx&isDonationWidget=0&processImmediate=1&referenceId=324324&returnUrl=XXXXXXXX&signatureMethod=HmacSHA256&signatureVersion=2

テストのために、出力をこのフォームに連結して貼り付けます

<form action="https://authorize.payments.amazon.com/pba/paypipeline" method="POST">
  <input type='hidden' name='abandonUrl' value='[confidential]'>
  <input type='hidden' name='accessKey' value='[confidential]'>
  <input type='hidden' name='amazonPaymentsAccountId' value='[confidential]'>
  <input type='hidden' name='amount' value='USD 3'>
  <input type='hidden' name='cobrandingStyle' value='logo'>
  <input type='hidden' name='collectShippingAddress' value='0'>
  <input type='hidden' name='description' value='sadasdd'>
  <input type='hidden' name='immediateReturn' value='1'>
  <input type='hidden' name='ipnUrl' value='[confidential]'>
  <input type='hidden' name='isDonationWidget' value='0'>
  <input type='hidden' name='processImmediate' value='1'>
  <input type='hidden' name='referenceId' value='324324'>
  <input type='hidden' name='returnUrl' value='[confidential]'>
  <input type='hidden' name='signatureMethod' value='HmacSHA256'>
  <input type='hidden' name='signatureVersion' value='2'>
  <input type='hidden' name='signature' value='fHSA+p37r5ooOJOUnjYBdhNFe/pAEg/KunAEOudUvGs='>
  <input type="submit">
</form>

アマゾンのドキュメントはこちら

http://docs.aws.amazon.com/AmazonSimplePay/latest/ASPAdvancedUserGuide/Sig2CreateSignature.html

署名を生成する方法

署名を作成するには

この手順の後半で必要になる、正規化されたクエリ文字列を作成します。

UTF-8 クエリ文字列コンポーネントをパラメーター名で自然なバイト順で並べ替えます。

パラメーターは、GET URI または POST 本文から取得できます (Content-Type が application/x-www-form-urlencoded の場合)。

次のルールに従って、パラメーター名と値を URL エンコードします。

RFC 3986 で定義されている予約されていない文字を URL エンコードしないでください。

これらの予約されていない文字は、A ~ Z、a ~ z、0 ~ 9、ハイフン (-)、アンダースコア (_)、ピリオド (.)、およびチルダ (~) です。

他のすべての文字を %XY でパーセント エンコードします。ここで、X と Y は 16 進数の 0 ~ 9 と大文字の AF です。

%XY%ZA... 形式の拡張 UTF-8 文字をパーセントエンコードします。

パーセントは、スペース文字を %20 としてエンコードします (一般的なエンコード スキームのように + ではありません)。

Note 現在、すべての AWS サービス パラメータ名は予約されていない文字を使用しているため、エンコードする必要はありません。ただし、将来の使用に備えて、予約文字を使用するパラメーター名を処理するコードを含めることができます。パラメーター値が空の場合でも、エンコードされたパラメーター名をエンコードされた値から等号 ( = ) (ASCII 文字 61) で区切ります。

名前と値のペアをアンパサンド ( & ) (ASCII コード 38) で区切ります。

次の疑似文法に従って、署名する文字列を作成します (「\n」は ASCII 改行を表します)。

StringToSign = HTTPVerb + "\n" + ValueOfHostHeaderInLowercase + "\n" + HTTPRequestURI + "\n" + CanonicalizedQueryString HTTPRequestURI コンポーネントは、クエリ文字列までの URI の HTTP 絶対パス コンポーネントですが、クエリ文字列は含まれません。HTTPRequestURI が空の場合は、スラッシュ ( / ) を使用します。

作成したばかりの文字列、キーとしてシークレット アクセス キー、ハッシュ アルゴリズムとして SHA256 または SHA1 を使用して、RFC 2104 準拠の HMAC を計算します。

詳細については、http://www.ietf.org/rfc/rfc2104.txt にアクセスしてください

結果の値を base64 に変換します。

結果の値を Signature リクエスト パラメータの値として使用します。

重要 要求で送信する最終的な署名は、RFC 3986 で指定されているように URL エンコードする必要があります (詳細については、 http://www.ietf.org/rfc/rfc3986.txtにアクセスしてください)。ツールキットの URL が最終的な要求をエンコードする場合、必要な署名の URL エンコードを処理します。ツールキットが最終リクエストを URL エンコードしない場合は、署名をリクエストに含める前に必ず URL エンコードしてください。最も重要なことは、署名が 1 回だけ URL エンコードされていることを確認することです。よくある間違いは、署名の形成中に URL を手動でエンコードし、ツールキットの URL がリクエスト全体をエンコードするときに再度エンコードすることです。ボタンを作成するための高度なプロセスについては、「ボタン フォームを動的に作成する」を参照してください。

次の例では、例を読みやすくするために新しい行が挿入されています。明示的な '\n' は改行が必要な場所で使用されます。

以下は、POST を使用した Amazon Simple Pay リクエストの例です。

前の例で StringToSign に使用する文字列の例を次に示します。

POST\n authorize.payments-sandbox.amazon.com\n /pba/paypipeline\n SignatureMethod=HmacSHA256 &SignatureVersion=2 &accessKey=YourCallerKey &amount=USD%201.1 &cobrandingStyle=logo &description=Test%20Widget &immediateReturn=0 &ipnUrl=http%3A %2F%2Fyourwebsite.com%2Fipn &processImmediate=1 &referenceId=YourReferenceId &returnUrl=http%3A%2F%2Fyourwebsite.com%2Freturn.html 署名を生成するその他の例については、「付録: サンプル コード」を参照してください。

ボタン フォームに正しく署名する方法については、「ボタン フォームに正しく署名する方法」を参照してください。

4

1 に答える 1

2

後世のために、ここに解決策があります:

1) シンプルな支払いボタンを台無しにしないでください - 代わりに FPS を使用してください

2) 無数の重複するドキュメントの中で、これが最も単純で明確であることがわかりました: http://docs.aws.amazon.com/AmazonFPS/latest/FPSBasicGuide/SendingaCBUIRequest.html

3) encodeURI ではなく、encodeURIComponent を使用してください - これは私の最大の最も苛立たしい間違いでした

このコードは、Amazon FPS リクエストに正しく署名します (hmac の暗号化と構成の nconf を想定しています)。

var crypto = require('crypto');
var _ = require('underscore');
var nconf = require('nconf').argv().env().file({
    file: "./config.json"
});
exports.azPayRequest=function (amount, desc,ref) {
  var params={
    "returnUrl": nconf.get("awsPayments:returnURL"), //callback
    "callerKey" : nconf.get("awsPayments:callerKey"), //aws id
    "callerReference": ref,
    "pipelineName":"SingleUse",
    "cobrandingStyle" :"logo",
    "currencyCode" :"USD",
    "transactionAmount" : amount,
    "paymentReason" : desc,
    "signatureMethod": "HmacSHA256",
    "signatureVersion" :"2"
    }

    /*
    StringToSign = HTTPVerb + "\n" +
    ValueOfHostHeaderInLowercase + "\n" +
    HTTPRequestURI + "\n" +         
    CanonicalizedQueryString <from the preceding step>
    */

    //sort parameters
    var p=_.pairs(params);
    var psorted=_.sortBy(p, function(p) { return p[0];});

    //method, host, path
    var method='GET';
    var host=nconf.get('awsPayments:host'); // e.g., authorize.payments.amazon.com;
    var path=nconf.get('awsPayments:path'); //e.g. /cobranded-ui/actions/start;

    //url encode parameters
    var qstring='';
    for(var i=0; i<psorted.length;i++) {
        psorted[i][0]=encodeURIComponent(psorted[i][0]);
        psorted[i][1]=encodeURIComponent(psorted[i][1]);
        qstring+=psorted[i][0]+'='+psorted[i][1];
        if (i<psorted.length-1) {qstring+='&';} 
    };

    //calculate hmac
    var nl=String.fromCharCode(10);
    var encode_request=method+nl+host+nl+path+nl+qstring;
    console.log("STRING TO ENCODE\n"+encode_request+'\n\n');
    var sig=crypto.createHmac("SHA256", nconf.get("awsPayments:awsSecretAccessKey"))
        .update(encode_request)
        .digest('base64');

    var url="https://"+host+path+"?"+qstring+'&signature='+encodeURIComponent(sig);

    return url;
}
于 2013-07-06T16:38:23.760 に答える