安全なお支払いの確認による認証

クレジット カードまたは銀行口座に対する強力な顧客認証(SCA)プロセスの一環として、安全なお支払いの確認(SPC)をご利用いただけます。WebAuthn は認証を行います(多くの場合、生体認証が使用されます)。WebAuthn は事前に登録する必要があります。詳細については、安全な支払い確認を登録するをご覧ください。

一般的な実装の仕組み

SPC の最も一般的な用途は、ユーザーが販売者のサイトで商品を購入する場合です。 サイトで、クレジット カード発行会社または銀行が支払人の認証を要求している場合。

認証ワークフロー。

認証フローを見ていきましょう。

  1. お客様が支払い認証情報(クレジット カードなど)を提示する 情報など)を販売者に提供します。
  2. 販売者が、支払い認証情報の対応するカード発行会社または銀行に質問する (証明書利用者または RP)に支払います。この 発生する可能性があります。 EMV® 3D セキュア
    • RP が販売者に SPC の使用を希望していて、ユーザーが以前に 登録されると、RP は、API によって登録された認証情報 ID のリストを チャレンジできます
    • 認証が不要な場合、販売者は認証を続行できます。 トランザクションを完了します。
  3. 認証が必要な場合は、ブラウザが SPC に対応しているかどうかを販売者が判断します。
    • ブラウザが SPC をサポートしていない場合は、既存の 認証フローについて説明します。
  4. 販売者が SPC を呼び出します。ブラウザに確認ダイアログが表示されます。
    • RP から渡された認証情報 ID がない場合は、 できます。 認証が成功したら、SPC 登録の使用を検討する 今後の認証を効率化します
  5. ユーザーは、金額と配送先の確認と認証を行います デバイスのロックを解除します。
  6. 販売者は認証によって認証情報を受け取ります。
  7. RP は販売者から認証情報を受け取り、その認証情報を検証する あります。
  8. RP がオーナー確認の結果を販売者に送信します。
  9. 販売者はユーザーに、支払いが行われたかどうかを示すメッセージを表示します。 成功または失敗です。
で確認できます。

機能検出

SPC がブラウザでサポートされているかどうかを確認するには、 canMakePayment()

販売者のウェブサイトで SPC の機能を検出するには、次のコードをコピーして貼り付けます。

const isSecurePaymentConfirmationSupported = async () => {
  if (!'PaymentRequest' in window) {
    return [false, 'Payment Request API is not supported'];
  }

  try {
    // The data below is the minimum required to create the request and
    // check if a payment can be made.
    const supportedInstruments = [
      {
        supportedMethods: "secure-payment-confirmation",
        data: {
          // RP's hostname as its ID
          rpId: 'rp.example',
          // A dummy credential ID
          credentialIds: [new Uint8Array(1)],
          // A dummy challenge
          challenge: new Uint8Array(1),
          instrument: {
            // Non-empty display name string
            displayName: ' ',
            // Transparent-black pixel.
            icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==',
          },
          // A dummy merchant origin
          payeeOrigin: 'https://non-existent.example',
        }
      }
    ];

    const details = {
      // Dummy shopping details
      total: {label: 'Total', amount: {currency: 'USD', value: '0'}},
    };

    const request = new PaymentRequest(supportedInstruments, details);
    const canMakePayment = await request.canMakePayment();
    return [canMakePayment, canMakePayment ? '' : 'SPC is not available'];
  } catch (error) {
    console.error(error);
    return [false, error.message];
  }
};

isSecurePaymentConfirmationSupported().then(result => {
  const [isSecurePaymentConfirmationSupported, reason] = result;
  if (isSecurePaymentConfirmationSupported) {
    // Display the payment button that invokes SPC.
  } else {
    // Fallback to the legacy authentication method.
  }
});

お客様を認証する

ユーザーを認証するには、次のように PaymentRequest.show() メソッドを呼び出します。 secure-payment-confirmation パラメータと WebAuthn パラメータ:

お支払い方法の data プロパティ(SecurePaymentConfirmationRequest)に指定する必要があるパラメータは次のとおりです。

パラメータ 説明
rpId RP 送信元のホスト名(RP ID)。
challenge リプレイ攻撃を防ぐランダムなチャレンジ。
credentialIds 認証情報 ID の配列。WebAuthn の認証では、allowCredentials プロパティは PublicKeyCredentialDescriptor オブジェクトの配列を受け入れますが、SPC では認証情報 ID のリストのみを渡します。
payeeName(任意) お支払い受取人の名前。
payeeOrigin お支払い受取人の出身地。上記のシナリオでは、送信元が販売者のものです。
instrument 画像リソースを指す displayName の文字列と icon の URL。リクエストを成功させるには、アイコンが正常に取得されて表示される必要があることを示す、iconMustBeShown のブール値(デフォルトは true)です(省略可)。
timeout トランザクションに署名するためのタイムアウト(ミリ秒)
extensions WebAuthn 呼び出しに拡張機能が追加されました。「payment」を指定する必要はありません作成します。

次のサンプルコードをご覧ください。

// After confirming SPC is available on this browser via a feature detection,
// fetch the request options cross-origin from the RP server.
const options = fetchFromServer('https://rp.example/spc-auth-request');
const { credentialIds, challenge } = options;

const request = new PaymentRequest([{
  // Specify `secure-payment-confirmation` as payment method.
  supportedMethods: "secure-payment-confirmation",
  data: {
    // The RP ID
    rpId: 'rp.example',

    // List of credential IDs obtained from the RP server.
    credentialIds,

    // The challenge is also obtained from the RP server.
    challenge,

    // A display name and an icon that represent the payment instrument.
    instrument: {
      displayName: "Fancy Card ****1234",
      icon: "https://rp.example/card-art.png",
      iconMustBeShown: false
    },

    // The origin of the payee (merchant)
    payeeOrigin: "https://merchant.example",

    // The number of milliseconds to timeout.
    timeout: 360000,  // 6 minutes
  }
}], {
  // Payment details.
  total: {
    label: "Total",
    amount: {
      currency: "USD",
      value: "5.00",
    },
  },
});

try {
  const response = await request.show();

  // response.details is a PublicKeyCredential, with a clientDataJSON that
  // contains the transaction data for verification by the issuing bank.
  // Make sure to serialize the binary part of the credential before
  // transferring to the server.
  const result = fetchFromServer('https://rp.example/spc-auth-response', response.details);
  if (result.success) {
    await response.complete('success');
  } else {
    await response.complete('fail');
  }
} catch (err) {
  // SPC cannot be used; merchant should fallback to traditional flows
  console.error(err);
}

.show() 関数の結果は、 PaymentResponse ただし、details には公開鍵認証情報が含まれており、 トランザクション データを含む clientDataJSON (payment) 。

生成された認証情報は、クロスオリジンで RP に転送する必要があります。 確認しました。

RP が取引を確認する方法

RP サーバーでトランザクション データを検証することは、 支払い処理を行います。

トランザクション データを確認するために、RP は WebAuthn の認証アサーションの検証プロセスに沿うことができます。 さらに、以下の要件を満たす必要があります。 payment を確認します。

clientDataJSON のペイロードの例:

{
  "type":"payment.get",
  "challenge":"SAxYy64IvwWpoqpr8JV1CVLHDNLKXlxbtPv4Xg3cnoc",
  "origin":"https://spc-merchant.glitch.me",
  "crossOrigin":false,
  "payment":{
    "rp":"spc-rp.glitch.me",
    "topOrigin":"https://spc-merchant.glitch.me",
    "payeeOrigin":"https://spc-merchant.glitch.me",
    "total":{
      "value":"15.00",
      "currency":"USD"
    },
    "instrument":{
      "icon":"https://cdn.glitch.me/94838ffe-241b-4a67-a9e0-290bfe34c351%2Fbank.png?v=1639111444422",
      "displayName":"Fancy Card 825809751248"
    }
  }
}
  • rp は RP のオリジンと一致します。
  • topOrigin は、RP が想定している最上位のオリジン( (上記の例では販売者の拠点など)。
  • payeeOrigin は、支払い受取人の送金元と一致しているはずです。 表示されます。
  • total が、本来表示されるはずの取引金額と一致している 提供します。
  • instrument が、指定する必要があるお支払い方法の詳細と一致している 表示されました。
const clientData = base64url.decode(response.clientDataJSON);
const clientDataJSON = JSON.parse(clientData);

if (!clientDataJSON.payment) {
  throw 'The credential does not contain payment payload.';
}

const payment = clientDataJSON.payment;
if (payment.rp !== expectedRPID ||
    payment.topOrigin !== expectedOrigin ||
    payment.payeeOrigin !== expectedOrigin ||
    payment.total.value !== '15.00' ||
    payment.total.currency !== 'USD') {
  throw 'Malformed payment information.';
}

すべての検証基準が満たされると、RP は 取引が成功したことを販売者に知らせます。

次のステップ