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. Dzięki temu użytkownicy mogą się uwierzytelniać, wybierając konto z listy kluczy dostępu, które mają do bieżącej witryny.

Wcześniejsze wersje kluczy bezpieczeństwa zostały zaprojektowane jako metody uwierzytelniania dwuetapowego i wymagały identyfikatorów potencjalnych danych logowania, a tym samym wpisania nazwy użytkownika. Dane logowania, które klucz bezpieczeństwa może znaleźć bez znajomości ich identyfikatorów, nazywane są danymi wykrywalnymi. Większość danych uwierzytelniających FIDO tworzonych obecnie to dane wykrywalne, zwłaszcza klucze dostępu przechowywane w menedżerze haseł lub na nowoczesnym kluczu bezpieczeństwa.

Aby mieć pewność, że dane logowania zostaną utworzone jako klucze dostępu (wykrywalne dane logowania), podczas tworzenia danych logowania określ residentKey i requireResidentKey.

Strony uzależnione mogą używać danych logowania możliwych do wykrycia, 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, które są identyfikowane przez właściwość user.name ustawioną w momencie tworzenia. Jeśli użytkownik wybierze jedną z nich, wartość user.id zostanie uwzględniona w wynikowym podpisie. Serwer może następnie użyć tego identyfikatora lub zwróconego identyfikatora danych logowania, aby wyszukać konto, zamiast wpisywać nazwę użytkownika.

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

requireResidentKey i residentKey

Aby utworzyć klucz dostępu, określ authenticatorSelection.residentKey i authenticatorSelection.requireResidentKey na navigator.credentials.create(), podając wartości wskazane 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': należy utworzyć wykrywalne dane logowania. Jeśli nie można go utworzyć, zwracany jest błąd NotSupportedError.
  • 'preferred': strona uzależniona preferuje utworzenie danych logowania możliwych do znalezienia, ale akceptuje też dane logowania niemożliwe do znalezienia.
  • 'discouraged': strona uzyskująca preferuje tworzenie danych logowania, których nie można znaleźć, ale akceptuje dane logowania, które można znaleźć.

requireResidentKey:

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

allowCredentials

Platformy zależne mogą używać allowCredentials na navigator.credentials.get(), aby kontrolować proces uwierzytelniania za pomocą klucza dostępu. Zwykle występują 3 rodzaje uwierzytelniania za pomocą klucza dostępu:

Dzięki danym logowania możliwym do wykrycia strony uzyskujące dostęp mogą wyświetlać modalny selektor konta, aby użytkownik mógł wybrać konto, na które chce się zalogować, a następnie przejść weryfikację. Jest to odpowiednie w przypadku procesu uwierzytelniania za pomocą klucza dostępu, który jest inicjowany przez naciśnięcie przycisku przeznaczonego do tego celu.

Aby uzyskać taki efekt, pomiń parametr allowCredentials w navigator.credentials.get() lub przekaż do niego pustą tablicę.

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

Wyświetlanie formularza autouzupełniania klucza dostępu

Opisany powyżej selektor konta w oknie modalnym sprawdza się, 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 pojawi 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 uniknąć wyświetlania tego interfejsu użytkownikom, którzy nie skonfigurowali klucza.

Zamiast tego wybór klucza dostępu może być uwzględniony w prośbach o autouzupełnianie pól w tradycyjnym formularzu logowania, obok zapisanych nazw użytkowników i haseł. Dzięki temu użytkownik z kluczami dostępu może „wypełnić” formularz logowania, wybierając klucz dostępu, użytkownicy z zapisanymi parami nazwy użytkownika i hasła mogą je wybrać, a użytkownicy, którzy nie mają ani jednego, ani drugiego, mogą wpisać nazwę użytkownika i hasło.

To rozwiązanie jest idealne, gdy strona uzależniona jest w trakcie migracji i używa zarówno haseł, jak i kluczy dostępu.

Aby uzyskać taki efekt, oprócz przekazania pustej tablicy do właściwości allowCredentials lub pominięcia parametru, określ mediation: 'conditional' w navigator.credentials.get() i dodaj adnotację do pola do wprowadzania danych username w HTML z autocomplete="username webauthn" lub pola do wprowadzania danych password z autocomplete="password webauthn".

Wywołanie navigator.credentials.get() nie spowoduje wyświetlenia żadnego interfejsu, ale jeśli użytkownik zaznaczy pole do wprowadzania danych z adnotacją, wszystkie 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 i dopiero wtedy obietnica zwrócona przez .get() zostanie rozwiązana z wynikiem. Jeśli użytkownik nie wybierze klucza dostępu, obietnica nigdy nie zostanie spełniona.

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=&qu>ot;username webauthn" ...

Więcej informacji o tym, jak utworzyć takie środowisko, znajdziesz w artykule Logowanie się za pomocą klucza dostępu przy użyciu autouzupełniania formularzy oraz w ćwiczeniu z programowania Wdrażanie kluczy dostępu z autouzupełnianiem formularzy w aplikacji internetowej.

Ponowne uwierzytelnianie

W niektórych przypadkach, np. gdy klucze dostępu są używane do ponownego uwierzytelniania, identyfikator użytkownika jest już znany. W takim przypadku chcemy użyć klucza dostępu bez wyświetlania przez przeglądarkę lub system operacyjny jakiejkolwiek formy selektora kont. Można to zrobić, przekazując listę identyfikatorów danych logowania w parametrze allowCredentials.

W takim przypadku, jeśli którekolwiek z wymienionych danych logowania są dostępne lokalnie, użytkownik jest natychmiast proszony o odblokowanie urządzenia. Jeśli nie, użytkownik zostanie poproszony o użycie innego urządzenia (telefonu lub klucza bezpieczeństwa) z prawidłowymi danymi logowania.

Aby to osiągnąć, podaj listę identyfikatorów danych logowania użytkownika. Platforma uzależniona powinna mieć możliwość ich wysłania, ponieważ użytkownik jest już znany. Podaj identyfikatory danych logowania jako obiekty PublicKeyCredentialDescriptor we właściwości allowCredentials w 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 tych elementów:

  • id: identyfikator danych uwierzytelniających klucza publicznego, który strona uzyskująca otrzymała podczas rejestracji klucza dostępu.
  • type: to pole jest zazwyczaj 'public-key'.
  • transports: wskazówka dotycząca transportów obsługiwanych przez urządzenie, na którym znajdują się te dane logowania. Jest używana przez przeglądarki do optymalizacji interfejsu, który prosi użytkownika o podłączenie urządzenia zewnętrznego. Ta lista, jeśli jest podana, powinna zawierać wynik wywołania funkcji getTransports() podczas rejestracji poszczególnych danych logowania.

Podsumowanie

Dane logowania możliwe do wykrycia znacznie ułatwiają logowanie się za pomocą klucza dostępu, ponieważ użytkownik nie musi wpisywać nazwy użytkownika. Dzięki połączeniu residentKey, requireResidentKey i allowCredentials dostawcy usług mogą zapewnić użytkownikom logowanie, które:

  • Wyświetl modalny selektor kont.
  • wyświetlać autouzupełnianie formularza klucza dostępu,
  • Ponowne uwierzytelnianie.

Używaj danych logowania możliwych do wykrycia z rozwagą. Dzięki temu możesz zaprojektować zaawansowane funkcje logowania za pomocą klucza dostępu, które będą dla użytkowników płynne i bardziej angażujące.