Potwierdzenie uwierzytelnienia za pomocą bezpiecznej płatności

Sprzedawcy mogą używać bezpiecznego potwierdzenia płatności (SPC) w ramach procesu silnego uwierzytelniania klienta (SCA) w przypadku danej karty kredytowej lub konta bankowego. WebAuthn przeprowadza uwierzytelnianie (często za pomocą danych biometrycznych). WebAuthn musi być zarejestrowany z wyprzedzeniem. Więcej informacji znajdziesz w artykule Rejestrowanie bezpiecznego potwierdzenia płatności.

Jak działa typowa implementacja

Najczęstszym zastosowaniem SPC jest sytuacja, gdy klient dokonuje zakupu w witrynie sprzedawcy, a wydawca karty kredytowej lub bank wymaga uwierzytelnienia płatnika.

Proces uwierzytelniania.

Omówmy proces uwierzytelniania:

  1. Klient przekazuje sprzedawcy dane do płatności (np. informacje o karcie kredytowej).
  2. Sprzedawca pyta wydawcę lub bank odpowiadający za dane uwierzytelniające (stroną korzystającą z usługi lub RP) o to, czy płatnik potrzebuje osobnego uwierzytelnienia. Takie wymiany mogą na przykład mieć miejsce w przypadku EMV® 3-D Secure.
    • Jeśli RP chce, aby sprzedawca korzystał z SPC, a użytkownik został wcześniej zarejestrowany, RP odpowiada listą identyfikatorów danych logowania zarejestrowanych przez płatnika oraz wyzwaniem.
    • Jeśli uwierzytelnianie nie jest wymagane, sprzedawca może kontynuować realizację transakcji.
  3. Jeśli uwierzytelnianie jest wymagane, sprzedawca decyduje, czy przeglądarka obsługuje SPC.
    • Jeśli przeglądarka nie obsługuje SPC, przejdź do bieżącego procesu uwierzytelniania.
  4. Sprzedawca używa SPC. Przeglądarka wyświetli okno potwierdzenia.
    • Jeśli z serwera RP nie otrzymasz żadnych identyfikatorów danych uwierzytelniających, użyj istniejącego procesu uwierzytelniania. Po pomyślnej weryfikacji rozważ użycie rejestracji SPC, aby usprawnić przyszłe uwierzytelnianie.
  5. Użytkownik potwierdza i uwierzytelnia kwotę oraz miejsce docelowe płatności, odblokowując urządzenie.
  6. Sprzedawca otrzymuje dane uwierzytelniające.
  7. RP otrzymuje dane logowania od sprzedawcy i sprawdza ich autentyczność.
  8. RP wysyła wyniki weryfikacji do sprzedawcy.
  9. Sprzedawca wyświetla użytkownikowi wiadomość, która informuje, czy płatność została zrealizowana, czy nie.

Wykrywanie cech

Aby sprawdzić, czy przeglądarka obsługuje SPC, możesz wysłać fałszywe wywołanie do przeglądarki canMakePayment().

Skopiuj i wklej ten kod, aby umożliwić wykrywanie SPC w witrynie sprzedawcy.

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

Uwierzytelnienie użytkownika

Aby uwierzytelnić użytkownika, wywołaj metodę PaymentRequest.show() z parametrami secure-payment-confirmation i WebAuthn:

Oto parametry, które należy podać w przypadku właściwości data formy płatności: SecurePaymentConfirmationRequest.

Parametr Opis
rpId Nazwa hosta strony objętej ograniczeniami jako identyfikator strony objętej ograniczeniami.
challenge losowe wyzwanie, które zapobiega atakom polegającym na odtwarzaniu.
credentialIds Tablica identyfikatorów danych logowania. W ramach uwierzytelniania WebAuthn właściwość allowCredentials akceptuje tablicę obiektów PublicKeyCredentialDescriptor, ale w SPC przekazujesz tylko listę identyfikatorów danych logowania.
payeeName (opcjonalnie) Nazwa odbiorcy płatności.
payeeOrigin Źródło danych odbiorcy. W tym scenariuszu jest to kraj sprzedawcy.
instrument ciąg znaków dla atrybutu displayName i adres URL dla atrybutu icon, który wskazuje zasób obrazów. Opcjonalna wartość logiczna (domyślnie true) dla parametru iconMustBeShown, która określa, że aby żądanie zostało zaakceptowane, ikona musi zostać pomyślnie pobrana i wyświetlona.
timeout Limit czasu na podpisanie transakcji w milisekundach
extensions Do wywołania WebAuthn dodano rozszerzenia. Nie musisz samodzielnie określać rozszerzenia „payment”.

Sprawdź ten przykładowy kod:

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

Funkcja .show() zwraca obiekt PaymentResponse, z tym że details zawiera klucz publiczny z clientDataJSON, który zawiera dane transakcji (payment) do weryfikacji przez RP.

Uzyskane dane uwierzytelniające muszą zostać przeniesione do RP w innej domenie i zweryfikowane.

Jak RP weryfikuje transakcję

Weryfikacja danych transakcji na serwerze RP jest najważniejszym krokiem w procesie płatności.

Aby zweryfikować dane transakcji, RP może wykonać proces weryfikacji oświadczenia uwierzytelniającego w WebAuthn. Dodatkowo musisz potwierdzić payment.

Przykładowy ładunek 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"
    }
  }
}
  • Wartość rp musi być zgodna z źródłem RP.
  • Wartość topOrigin odpowiada domencie najwyższego poziomu oczekiwanemu przez RP (w przykładzie powyżej jest to domena sprzedawcy).
  • Wartość payeeOrigin odpowiada źródłu danych odbiorcy płatności, które powinny zostać wyświetlone użytkownikowi.
  • Wartość total odpowiada kwocie transakcji, która powinna zostać wyświetlona użytkownikowi.
  • Wartość instrument odpowiada szczegółom instrumentu płatniczego, które powinny zostać wyświetlone użytkownikowi.
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.';
}

Gdy wszystkie kryteria weryfikacji zostaną spełnione, RP może poinformować sprzedawcę, że transakcja została zrealizowana.

Dalsze kroki