Szczegółowe dane logowania możliwe do znalezienia

Choć dane FIDO, takie jak klucze dostępu, mają na celu zastąpienie haseł, ale większość z nich pozwala też na uwolnienie użytkownika od wpisania nazwy użytkownika. Dzięki temu użytkownicy będą mogli się uwierzytelnić przez wybranie konta z listy kluczy dostępu, które mają oni w bieżącej witrynie.

Wcześniejsze wersje kluczy bezpieczeństwa były zaprojektowane jako metody uwierzytelniania dwuetapowego i wymagały identyfikatorów potencjalnych danych logowania, więc wymagały podania nazwy użytkownika. Dane logowania, które klucz bezpieczeństwa może znaleźć bez poznania ich identyfikatorów, są nazywane danymi uwierzytelniającymi. Większość utworzonych obecnie danych logowania FIDO to wykrywalne dane logowania. W szczególności klucze są przechowywane w menedżerze haseł lub na nowoczesnym kluczu bezpieczeństwa.

Aby mieć pewność, że dane logowania będą wykrywalne, podczas tworzenia klucza dostępu określ wartości residentKey i requireResidentKey.

Podmioty uzależnione mogą używać wykrywalnych danych logowania, pomijając allowCredentials podczas uwierzytelniania przy użyciu klucza dostępu. W takich przypadkach przeglądarka lub system wyświetla użytkownikowi listę dostępnych kluczy dostępu określonych przez właściwość user.name ustawioną w momencie tworzenia. Jeśli użytkownik wybierze jedną z nich, w wynikowym podpisie zostanie uwzględniona wartość user.id. Serwer może następnie użyć tego lub zwróconego identyfikatora danych logowania do wyszukania konta zamiast podanej nazwy użytkownika.

Interfejsy użytkownika selektora kont, takie jak omówione wcześniej, nigdy nie pokazują danych logowania, których nie można wykryć.

requireResidentKeyresidentKey

Aby utworzyć możliwe do znalezienia dane logowania, określ authenticatorSelection.residentKey i authenticatorSelection.requireResidentKey w navigator.credentials.create() przy użyciu poniższych wartości.

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ć możliwe do znalezienia dane logowania. Jeśli nie można go utworzyć, zwracany jest element NotSupportedError.
  • 'preferred': w grupie objętej ograniczeniami preferujemy tworzenie danych logowania możliwych do znalezienia, ale akceptowane są takie, których nie można wykryć.
  • 'discouraged': grupa z ograniczonym dostępem preferuje tworzenie niewykrywalnych danych logowania, ale akceptuje też możliwe do znalezienia dane logowania.

requireResidentKey:

  • Ta właściwość została zachowana na potrzeby zgodności wstecznej z wcześniejszą wersją specyfikacji WebAuthn Level 1. Ustaw jako true, jeśli residentKey ma wartość 'required'. W przeciwnym razie ustaw wartość false.

allowCredentials

RP mogą używać allowCredentials w systemie navigator.credentials.get(), aby kontrolować uwierzytelnianie przy użyciu klucza dostępu. Zazwyczaj są 3 rodzaje uwierzytelniania przy użyciu klucza dostępu:

Dzięki wykrywaniu danych logowania punkty z ograniczeniami mogą wyświetlać modalny selektor konta, aby użytkownik mógł wybrać konto, na które chce się zalogować, a następnie przejść do weryfikacji użytkownika. Jest to przydatne w przypadku procesu uwierzytelniania za pomocą klucza dostępu inicjowanego przez naciśnięcie przycisku przeznaczonego do uwierzytelniania klucza dostępu.

Aby osiągnąć odpowiedni komfort użytkownika, pomiń lub przekaż pustą tablicę do parametru allowCredentials w tabeli 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;
  
  // ...
}

Pokazuj autouzupełnianie formularzy klucza dostępu

Opisany powyżej modalny selektor kont działa dobrze, gdy większość użytkowników korzysta z kluczy dostępu i ma je dostępne na urządzeniu lokalnym. Użytkownik, który nie ma lokalnych kluczy dostępu, nadal wyświetli okno modalne, w którym będzie mógł przedstawić klucz z innego urządzenia. Podczas przenoszenia użytkowników na klucze dostępu możesz unikać korzystania z tego interfejsu w przypadku użytkowników, którzy jeszcze go nie skonfigurowali.

Wybór klucza dostępu może być natomiast składany w prompty autouzupełniania pól w tradycyjnym formularzu logowania razem z zapisanymi nazwami użytkowników i hasłami. Dzięki temu użytkownik mający klucze dostępu może „wypełnić” formularz logowania, wybierając swój klucz, użytkownicy z zapisaną parą nazwy użytkownika i hasła mogą wybrać te pary, a użytkownicy, którzy nie mają żadnego z nich, nadal będą mogli wpisać swoją nazwę użytkownika i hasło.

Takie środowisko jest idealne, gdy RP jest przeprowadzany w trakcie migracji, gdy łączy użycie haseł i kluczy dostępu.

Aby zadbać o wygodę użytkowników, oprócz przekazania pustej tablicy do właściwości allowCredentials lub pominięcia parametru ustaw parametr mediation: 'conditional' w polu navigator.credentials.get(), a do pola do wprowadzania danych HTML username dodaj adnotację autocomplete="username webauthn" lub password wartością 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 adnotacjami, w opcjach autouzupełniania zostaną uwzględnione wszystkie dostępne klucze dostępu. Jeśli użytkownik wybierze jedną z nich, przejdzie standardową weryfikację odblokowania urządzenia, a jedynie wtedy odpowiedź otrzymana przez usługę .get() zareaguje wraz z wynikiem. Jeśli użytkownik nie wybierze klucza dostępu, obietnica nigdy nie zostanie cofnięta.

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" ...>

Informacje o tym, jak zapewnić użytkownikom większą wygodę, znajdziesz w ćwiczeniach z programowania dotyczących logowania się przy użyciu klucza dostępu w autouzupełnianiu formularzy oraz wdrażania kluczy dostępu z autouzupełnianiem formularzy w aplikacji internetowej.

Ponowne uwierzytelnianie

W niektórych przypadkach, np. w przypadku użycia kluczy do ponownego uwierzytelniania, identyfikator użytkownika jest już znany. W tym przypadku chcemy użyć klucza dostępu bez wyświetlania w przeglądarce lub systemie operacyjnym jakiejkolwiek formy selektora konta. Można to osiągnąć, przekazując listę identyfikatorów danych logowania w parametrze allowCredentials.

W takim przypadku, jeśli któreś z nazwanych danych logowania są dostępne lokalnie, użytkownik od razu zostanie poproszony o odblokowanie urządzenia. W przeciwnym razie użytkownik zostanie poproszony o przedstawienie innego urządzenia (telefonu lub klucza bezpieczeństwa) z ważnymi danymi logowania.

Aby zapewnić takie wrażenia użytkownikom, podaj listę identyfikatorów danych logowania użytkownika. Grupa z ograniczonym dostępem powinna mieć możliwość wysyłania do nich zapytań, bo użytkownik jest już znany. Podaj identyfikatory danych logowania jako obiekty PublicKeyCredentialDescriptor we właściwości allowCredentials w regionie 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 klucza publicznego, który partner dostępu uzyskał podczas rejestracji klucza.
  • type: to pole jest zazwyczaj 'public-key'.
  • transports: wskazówka dotycząca transportu obsługiwanego przez urządzenie, na którym znajduje się te dane logowania, używana przez przeglądarki do optymalizacji UI, która prosi użytkownika o podanie urządzenia zewnętrznego. Jeśli ta lista jest podana, powinna zawierać wynik wywołania getTransports() podczas rejestracji poszczególnych danych logowania.

Podsumowanie

Wykrywalne dane logowania znacznie ułatwiają logowanie przy użyciu klucza, ponieważ pozwalają na pominięcie wpisywania nazwy użytkownika. Dzięki połączeniu residentKey, requireResidentKey i allowCredentials grupy objęte ograniczeniami umożliwiają logowanie, które:

  • Pokaż modalny selektor kont.
  • Pokazuj autouzupełnianie formularzy klucza dostępu.
  • Ponowne uwierzytelnianie.

Rozsądnie używaj wykrywalnych danych logowania. W ten sposób możesz zaprojektować zaawansowane funkcje logowania przy użyciu kluczy dostępu, które będą płynniej dostępne dla użytkowników i będą bardziej skłonne do interakcji.