Potwierdzenie uwierzytelnienia za pomocą bezpiecznej płatności

Eiji Kitamura
Eiji Kitamura

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ęściej używa się SPC, gdy klient dokonuje zakupu w witrynie sprzedawcy, a wystawca karty kredytowej lub bank wymaga uwierzytelnienia płatnika.

Proces uwierzytelniania.

Przyjrzyjmy się procesowi uwierzytelniania:

  1. Klient podaje sprzedawcy swoje dane uwierzytelniające płatność (np. dane karty kredytowej).
  2. Jeśli płatnik wymaga osobnego uwierzytelniania, sprzedawca pyta właściwego wystawcę danych uwierzytelniających lub banku (podmiot uzależnionych lub podmiot zależny). 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 uwierzytelnienie nie jest potrzebne, sprzedawca może kontynuować transakcję.
  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 dotychczasowego 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 komunikat informujący o tym, 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 wykryć 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ć we właściwości SecurePaymentConfirmationRequest formy płatności: data.

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) Imię i nazwisko odbiorcy płatności.
payeeOrigin ��ródło danych odbiorcy. W przypadku opisanego wyżej scenariusza jest to kraj pochodzenia sprzedawcy.
instrument Ciąg znaków dla displayName i adres URL dla icon, który wskazuje zasób obrazu. 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, ale details zawiera dane uwierzytelniające klucza publicznego z clientDataJSON, który zawiera dane transakcji (payment) na potrzeby weryfikacji przez RP.

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

Jak RP weryfikuje transakcję

Zweryfikowanie danych transakcji na serwerze RP jest najważniejszym etapem procesu płatności.

Aby zweryfikować dane transakcji, RP może wykonać proces weryfikacji oświadczenia uwierzytelniającego w WebAuthn. Musi też zweryfikować 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