Mit sicherer Zahlungsbestätigung authentifizieren

Händler können die sichere Zahlungsbestätigung (Secure Payment Confirmation, SPC) als Teil eines Prozesses 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 über biometrische Verfahren). WebAuthn muss vorab registriert werden. Weitere Informationen finden Sie unter Sichere Zahlungsbestätigung registrieren.

So funktioniert eine typische Implementierung

Die SPC wird am häufigsten verwendet, wenn ein Kunde auf der Website eines Händlers einen Kauf tätigt und der Kreditkartenaussteller oder die Bank die Authentifizierung des Zahlungspflichtigen verlangt.

Authentifizierungsablauf

Sehen wir uns den Authentifizierungsablauf an:

  1. Ein Kunde stellt dem Händler seine Zahlungsdaten (z. B. Kreditkarteninformationen) zur Verfügung.
  2. Der Händler fragt den Aussteller oder die Bank der Zahlungsanmeldedaten (Relying Party, RP), ob der Zahlungspflichtige eine separate Authentifizierung benötigt. Dies kann beispielsweise bei EMV® 3-D Secure der Fall sein.
    • Wenn der RP möchte, 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 Bestätigungsanfrage.
    • Wenn keine Authentifizierung erforderlich ist, kann der Händler die Transaktion abschließen.
  3. Wenn eine Authentifizierung erforderlich ist, prüft der Händler, ob der Browser SPC unterstützt.
    • Wenn der Browser SPC nicht unterstützt, fahren Sie mit dem vorhandenen Authentifizierungsablauf fort.
  4. Der Händler ruft SPC auf. Im Browser wird ein Bestätigungsdialogfeld angezeigt.
    • Wenn vom RP keine Anmeldedaten-IDs übergeben werden, greife auf den vorhandenen Authentifizierungsablauf zurück. Nach einer erfolgreichen Authentifizierung kannst du die SPC-Registrierung verwenden, um zukünftige Authentifizierungen zu vereinfachen.
  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 Anmeldedaten von der Authentifizierung.
  7. Der RP empfängt die Anmeldedaten vom Händler und überprüft deren Echtheit.
  8. Der RP sendet die Überprüfungsergebnisse an den Händler.
  9. Der Händler zeigt dem Nutzer eine Nachricht an, um ihm mitzuteilen, ob die Zahlung erfolgreich war oder nicht.

Funktionserkennung

Wenn Sie prüfen möchten, ob SPC im Browser unterstützt wird, können Sie einen gefälschten Anruf an canMakePayment() senden.

Kopieren Sie den folgenden Code, um die Funktion zur Erkennung von Sonderangebotspreisen auf der Website eines Händlers zu aktivieren.

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

Rufen Sie zum Authentifizieren des Nutzers die PaymentRequest.show()-Methode mit den Parametern secure-payment-confirmation und WebAuthn auf:

Hier sind die Parameter, die du für die data-Eigenschaft der Zahlungsmethode (SecurePaymentConfirmationRequest) angeben solltest.

Parameter Beschreibung
rpId Der Hostname des RP-Ursprungs als RP-ID.
challenge Eine zufällige Herausforderung, die Wiederholungsangriffe verhindert.
credentialIds Ein Array von Anmeldedaten-IDs. Bei der WebAuthn-Authentifizierung akzeptiert das Attribut allowCredentials ein Array von PublicKeyCredentialDescriptor-Objekten. Bei der SPC-Authentifizierung geben Sie jedoch nur eine Liste von Anmeldedaten-IDs an.
payeeName (optional) Name des Zahlungsempfängers.
payeeOrigin Der Ursprung des Zahlungsempfängers. Im oben genannten Szenario ist das der Ursprung des Händlers.
instrument Ein String für displayName und eine URL für icon, die auf eine Bildressource verweist. Ein optionales boolesches Attribut (Standardwert: true) für iconMustBeShown, das angibt, dass ein Symbol abgerufen und angezeigt werden muss, damit die Anfrage erfolgreich ist.
timeout Zeitlimit für die Signatur der Transaktion in Millisekunden
extensions Dem WebAuthn-Aufruf wurden Erweiterungen hinzugefügt. Sie müssen die Erweiterung „payment“ 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 .show()-Funktion führt zu einem PaymentResponse-Objekt. Der Unterschied besteht darin, dass details eine Public-Key-Anmeldedaten mit einer clientDataJSON enthält, die die Transaktionsdaten (payment) zur Überprüfung durch den RP enthält.

Die resultierenden Anmeldedaten müssen plattformübergreifend an den RP übertragen und bestätigt werden.

So bestätigt der RP die Transaktion

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

Um die Transaktionsdaten zu überprüfen, kann der RP den Überprüfungsprozess für Authentifizierungsbestätigungen von WebAuthn befolgen. Außerdem muss er die payment bestätigen.

Beispielnutzlast der 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"
    }
  }
}
  • Die rp stimmt mit dem Ursprung des RP überein.
  • topOrigin stimmt mit dem erwarteten Ursprung der obersten Ebene überein, also mit dem Ursprung des Händlers im Beispiel oben.
  • Die payeeOrigin stimmt mit dem Ursprung des Zahlungsempfängers überein, der dem Nutzer angezeigt werden sollte.
  • Der total stimmt mit dem Transaktionsbetrag überein, der dem Nutzer angezeigt werden sollte.
  • instrument stimmt mit den Details des Zahlungsmittels überein, die dem Nutzer angezeigt werden sollten.
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 erfüllt wurden, kann der RP dem Händler mitteilen, dass die Transaktion erfolgreich war.

Nächste Schritte