Mit sicherer Zahlungsbestätigung authentifizieren

Eiji Kitamura
Eiji Kitamura

Händler können die sichere Zahlungsbestätigung (SPC) als Teil eines Verfahrens zur starken Kundenauthentifizierung (Strong Customer Authentication, SCA) für eine bestimmte Kreditkarte oder ein bestimmtes Bankkonto verwenden. WebAuthn führt die Authentifizierung durch (häufig durch biometrische Verfahren). WebAuthn muss im Voraus registriert werden. Weitere Informationen dazu finden Sie unter Sichere Zahlungsbestätigung registrieren.

Funktionsweise einer typischen Implementierung

Die häufigste Verwendung von SPC ist, wenn ein Kunde einen Kauf auf der Website eines Händlers tätigt und der Kreditkartenaussteller oder die Bank eine Authentifizierung des Zahlers verlangt.

Authentifizierungsworkflow.

Gehen wir den Authentifizierungsvorgang durch:

  1. Ein Kunde stellt dem Händler seine Anmeldedaten für Zahlungen (z. B. Kreditkartendaten) zur Verfügung.
  2. Der Händler fragt den Aussteller der Zahlungsanmeldedaten oder die Bank (die vertrauende Partei oder RP) an, ob der Zahlende eine separate Authentifizierung benötigt. Dieser Austausch kann beispielsweise mit EMV® 3-D Secure stattfinden.
    • Wenn der Händler wünscht, dass der Händler SPC verwendet, und der Nutzer sich zuvor registriert hat, antwortet der RP mit einer Liste der vom Zahlungspflichtigen registrierten Anmeldedaten-IDs und einer Identitätsbestätigung.
    • Wenn keine Authentifizierung erforderlich ist, kann der Händler die Transaktion fortsetzen.
  3. Wenn eine Authentifizierung erforderlich ist, entscheidet der Händler, ob der Browser SPC unterstützt.
    • Wenn der Browser SPC nicht unterstützt, fahren Sie mit dem vorhandenen Authentifizierungsvorgang fort.
  4. Der Händler ruft SPC auf. Im Browser wird ein Bestätigungsdialogfeld angezeigt.
    • Wenn keine Anmeldedaten-IDs vom RP weitergegeben werden, greifen Sie auf den vorhandenen Authentifizierungsvorgang zurück. Nach einer erfolgreichen Authentifizierung können Sie die SPC-Registrierung verwenden, um zukünftige Authentifizierungen zu optimieren.
  5. Der Nutzer bestätigt und authentifiziert den Betrag und das Ziel der Zahlung, indem er das Gerät entsperrt.
  6. Der Händler erhält von der Authentifizierung ein Ausweisdokument.
  7. Das RP erhält die Anmeldedaten vom Händler und überprüft dessen Authentizität.
  8. Das RP sendet die Bestätigungsergebnisse an den Händler.
  9. Der Händler zeigt dem Nutzer eine Nachricht an, um anzugeben, ob die Zahlung erfolgreich war oder fehlgeschlagen ist.

Funktionserkennung

Um festzustellen, ob SPC im Browser unterstützt wird, können Sie einen gefälschten Aufruf an canMakePayment() senden.

Kopieren Sie den folgenden Code und fügen Sie ihn ein, um die SPC (Feature-Erkennung) auf der Website eines Händlers zu erkennen.

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.
  }
});

Nutzer authentifizieren

Um den Nutzer zu authentifizieren, rufen Sie die Methode PaymentRequest.show() mit den Parametern secure-payment-confirmation und WebAuthn auf:

Folgende Parameter müssen Sie für die data-Property SecurePaymentConfirmationRequest der Zahlungsmethode angeben.

Parameter Beschreibung
rpId Der Hostname des RP-Ursprungs als RP-ID.
challenge Eine zufällige Herausforderung, die Replay-Angriffe verhindert.
credentialIds Ein Array von Anmeldedaten-IDs. Bei der Authentifizierung von WebAuthn akzeptiert die allowCredentials-Property ein Array von PublicKeyCredentialDescriptor-Objekten, bei SPC übergeben Sie jedoch nur eine Liste mit Anmeldedaten-IDs.
payeeName (optional) Name des Zahlungsempfängers
payeeOrigin Der Ursprung des Zahlungsempfängers. Im oben genannten Szenario ist dies der Ursprung des Händlers.
instrument Ein String für displayName und eine URL für icon, die auf eine Bildressource verweist. Ein optionaler boolescher Wert (standardmäßig true) für iconMustBeShown, der angibt, dass ein Symbol erfolgreich abgerufen und angezeigt werden muss, damit die Anfrage erfolgreich ist.
timeout Zeitlimit zum Signieren der Transaktion in Millisekunden
extensions Erweiterungen wurden dem WebAuthn-Aufruf hinzugefügt. Sie müssen die Zahlungserweiterung nicht selbst angeben.

Sehen Sie sich diesen Beispielcode an:

// 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);
}

Die Funktion .show() führt zu einem PaymentResponse-Objekt, mit dem Unterschied, dass details öffentliche Schlüsselanmeldedaten mit einem clientDataJSON enthält, der die Transaktionsdaten (payment) zur Überprüfung durch den RP enthält.

Die resultierenden Anmeldedaten müssen ursprungsübergreifend an das RP übertragen und verifiziert werden.

So überprüft das RP die Transaktion

Die Überprüfung der Transaktionsdaten auf dem RP-Server ist der wichtigste Schritt im Zahlungsprozess.

Zum Verifizieren der Transaktionsdaten kann der RP den Prozess der Authentifizierungsbestätigung von WebAuthn befolgen. Außerdem muss er payment verifizieren.

Eine Beispielnutzlast von 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 stimmt mit dem Ursprung des RP überein.
  • topOrigin entspricht dem Herkunftsort der obersten Ebene, die vom RP erwartet wird (im Beispiel oben der Herkunftsort des Händlers).
  • Der payeeOrigin stimmt mit dem Ursprung des Zahlungsempfängers überein, der dem Nutzer hätte angezeigt werden sollen.
  • total stimmt mit dem Transaktionsbetrag überein, der dem Nutzer hätte angezeigt werden sollen.
  • instrument stimmt mit den Details des Zahlungsmittels überein, die dem Nutzer hätte angezeigt werden sollen.
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.';
}

Nachdem alle Überprüfungskriterien bestanden wurden, kann der RP den Händler darüber informieren, dass die Transaktion erfolgreich war.

Nächste Schritte