Szczegółowe dane logowania dostępne do znalezienia

Dane logowania FIDO, takie jak klucze dostępu, mają zastąpić hasła, ale większość z nich może też uwolnić użytkownika od konieczności wpisywania nazwy użytkownika. Umożliwia to użytkownikom uwierzytelnianie się przez wybranie konta z listy kluczy dostępu do bieżącej witryny.

Wcześniejsze wersje kluczy bezpieczeństwa były zaprojektowane jako metody uwierzytelniania dwuetapowego i wymagały identyfikatorów potencjalnych danych uwierzytelniających, co wymagało wpisania nazwy użytkownika. Dane uwierzytelniające, które klucz bezpieczeństwa może znaleźć bez znajomości ich identyfikatorów, nazywamy danymi uwierzytelniania możliwymi do odkrycia. Większość danych uwierzytelniających FIDO tworzonych obecnie to dane uwierzytelniające, które można wykryć, zwłaszcza klucze dostępu przechowywane w menedżerze haseł lub na nowoczesnym kluczu bezpieczeństwa.

Aby mieć pewność, że dane logowania są tworzone jako klucze dostępu (dane logowania, które można wykryć), podczas ich tworzenia podaj wartości residentKeyrequireResidentKey.

Użytkownicy mogą używać danych logowania, które można wykryć, pomijając allowCredentials podczas uwierzytelniania za pomocą klucza dostępu. W takich przypadkach przeglądarka lub system wyświetla użytkownikowi listę dostępnych kluczy dostępu z uwzględnieniem właściwości user.name ustawionej podczas tworzenia. Jeśli użytkownik wybierze jedną z nich, wartość user.id zostanie uwzględniona w podpisanym dokumencie. Serwer może użyć tego identyfikatora lub zwróconego identyfikatora danych logowania, aby wyszukać konto zamiast wpisanej nazwy użytkownika.

Interfejsy selektora kont, takie jak omówione wcześniej, nigdy nie wyświetlają niewykrywalnych danych logowania.

requireResidentKeyresidentKey

Aby utworzyć klucz dostępu, określ wartości authenticatorSelection.residentKeyauthenticatorSelection.requireResidentKey na navigator.credentials.create() w sposób podany poniżej.

async function register () {
  // ...

  const publicKeyCredentialCreationOptions = {
    // ...
    authenticatorSelection: {
      authenticatorAttachment: 'platform',
      residentKey: 'required',
      requireResidentKey: true,
    }
  };

  const credential = await navigator.credentials.create({
    publicKey: publicKeyCredentialCreationOptions
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;

  // ...
}

residentKey:

  • 'required': musisz utworzyć dane logowania, które są widoczne dla innych. Jeśli nie można go utworzyć, zwracana jest wartość NotSupportedError.
  • 'preferred': RP preferuje tworzenie danych logowania możliwych do znalezienia, ale akceptuje dane logowania niemożliwe do znalezienia.
  • 'discouraged': RP woli utworzyć niewykrywalne dane logowania, ale akceptuje wykrywalne dane logowania.

requireResidentKey:

  • Ta właściwość jest zachowana ze względu na zgodność z poziomem 1 specyfikacji WebAuthn, czyli starszą wersją specyfikacji. Ustaw tę wartość na true, jeśli residentKey to 'required'. W przeciwnym razie ustaw ją na false.

allowCredentials

Reprezentanci mogą używać allowCredentialsnavigator.credentials.get(), aby kontrolować uwierzytelnianie za pomocą klucza. Zwykle występują 3 typy uwierzytelniania za pomocą klucza dostępu:

Dzięki możliwości wyświetlania danych logowania dostawcy usług mogą wyświetlić użytkownikowi okno wyboru konta, w którym może on wybrać konto, na którym chce się zalogować, a następnie przejść weryfikację. Jest to odpowiednie rozwiązanie w przypadku procesu uwierzytelniania za pomocą klucza, który jest inicjowany przez naciśnięcie przycisku przeznaczonego do uwierzytelniania za pomocą klucza.

Aby uzyskać taki efekt, pomiń parametr allowCredentials lub przekaż mu pusty tablic w funkcji navigator.credentials.get().

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

Pokaż autouzupełnianie formularza klucza dostępu

Opisywany powyżej modalny selektor kont działa dobrze, jeśli większość użytkowników korzysta z kluczy dostępu i ma je dostępne na urządzeniu lokalnym. W przypadku użytkownika, który nie ma lokalnych kluczy dostępu, nadal wyświetla się okno modalne z prośbą o podanie klucza dostępu z innego urządzenia. Podczas przenoszenia użytkowników na klucze dostępu możesz unikać tego interfejsu w przypadku użytkowników, którzy nie skonfigurowali jeszcze kluczy.

Zamiast tego wybór klucza dostępu może być uwzględniony w prośbach autouzupełniania w polach tradycyjnego formularza logowania, obok zapisanych nazw użytkowników i haseł. Dzięki temu użytkownik z kluczem dostępu może „wypełnić” formularz logowania, wybierając klucz dostępu, użytkownicy z zapisanymi nazwami użytkowników i hasłami mogą wybrać te dane, a użytkownicy bez tych danych mogą wpisać swoją nazwę użytkownika i hasło.

Takie rozwiązanie jest idealne, gdy RP przechodzi proces migracji, używając zarówno haseł, jak i kluczy dostępu.

Aby uzyskać takie działanie, oprócz przekazania pustego tablicy do właściwości allowCredentials lub pominięcia parametru, określ mediation: 'conditional' w przypadku navigator.credentials.get() i opatrz pole wejściowe HTML username atrybutem autocomplete="username webauthn" lub pole wejściowe password atrybutem autocomplete="password webauthn".

Wywołanie navigator.credentials.get() nie spowoduje wyświetlenia żadnego interfejsu użytkownika, ale jeśli użytkownik skoncentruje się na opatrzonym adnotacją polu wprowadzania danych, dostępne klucze dostępu zostaną uwzględnione w opcjach autouzupełniania. Jeśli użytkownik wybierze jedną z nich, przejdzie standardową weryfikację odblokowania urządzenia. Dopiero wtedy obietnica zwrócona przez .get() zostanie zrealizowana. Jeśli użytkownik nie wybierze klucza dostępu, obietnica nigdy się nie zrealizuje.

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const cred = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal,
    // Specify 'conditional' to activate conditional UI
    mediation: 'conditional'
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>

Więcej informacji o tym, jak tworzyć takie rozwiązania, znajdziesz w artykule Logowanie się za pomocą klucza dostępu przez autouzupełnianie formularzy oraz w ćwiczeniach z programowania Wdrażanie kluczy dostępu z autouzupełnianiem formularzy w aplikacji internetowej.

Ponowne uwierzytelnianie

W niektórych przypadkach, np. gdy do ponownego uwierzytelnienia używane są klucze dostępu, identyfikator użytkownika jest już znany. W tym przypadku chcielibyśmy użyć klucza dostępu bez wyświetlania przez przeglądarkę lub system operacyjny dowolnej formy selektora konta. Aby to zrobić, prześlij listę identyfikatorów danych logowania w parametrze allowCredentials.

W takim przypadku, jeśli na urządzeniu są dostępne jakiekolwiek nazwane dane logowania, użytkownik od razu otrzyma prośbę o odblokowanie urządzenia. W przeciwnym razie użytkownik zostanie poproszony o przedstawienie innego urządzenia (telefonu lub klucza bezpieczeństwa) z prawidłowymi danymi logowania.

Aby to umożliwić, podaj listę identyfikatorów danych logowania dla logującego się użytkownika. RP powinien mieć możliwość wysłania zapytania do tych usług, ponieważ użytkownik jest już znany. Podaj identyfikatory danych logowania jako obiekty PublicKeyCredentialDescriptor w przypadku właściwości allowCredentials w elementach navigator.credentials.get().

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // Provide a list of PublicKeyCredentialDescriptors:
    allowCredentials: [{
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, {
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, ...]
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

Obiekt PublicKeyCredentialDescriptor składa się z:

  • id: identyfikator poświadczeń klucza publicznego uzyskanych przez RP podczas rejestracji klucza dostępu.
  • type: to pole zwykle ma wartość 'public-key'.
  • transports: wskazówka dotycząca transportu obsługiwanego przez urządzenie zawierające te dane logowania. Jest ona używana przez przeglądarki do optymalizacji interfejsu, który prosi użytkownika o przedstawienie urządzenia zewnętrznego. Ta lista, jeśli zostanie podana, powinna zawierać wynik wywołania funkcji getTransports() podczas rejestracji każdego zestawu danych.

Podsumowanie

Dane logowania, które można znaleźć, znacznie ułatwiają logowanie się za pomocą klucza dostępu, ponieważ pozwalają pominąć wpisywanie nazwy użytkownika. Dzięki połączeniu funkcji residentKey, requireResidentKeyallowCredentials partnerzy reklamowi mogą korzystać z logowania, które:

  • Pokaż okno modalne z selektorem konta.
  • Wyświetlanie autouzupełniania formularza klucza dostępu.
  • Ponowne uwierzytelnianie.

Rozważnie używaj danych logowania, które są dostępne dla innych. Dzięki temu możesz zaprojektować zaawansowane funkcje logowania za pomocą klucza dostępu, które będą wygodne dla użytkowników i zwiększą ich zaangażowanie.