Logowanie się za pomocą klucza dostępu w ramach autouzupełniania formularzy

Utwórz sposób logowania, który korzysta z kluczy dostępu, a jednocześnie umożliwia obsługę obecnych haseł.

Klucze dostępu zastępują hasła i sprawiają, że konta użytkowników w internecie są bezpieczniejsze, prostsze i łatwiejsze w obsłudze. Jednak przejście z uwierzytelniania opartego na haśle na klucz dostępu może skomplikować wrażenia użytkowników. Używanie autouzupełniania formularzy do sugerowania kluczy dostępu może pomóc w stworzeniu ujednoliconego procesu.

Dlaczego do logowania się za pomocą klucza dostępu warto używać autouzupełniania formularzy?

Dzięki kluczowi dostępu użytkownik może logować się w witrynie przy użyciu odcisku palca, wizerunku twarzy lub kodu PIN urządzenia.

W idealnej sytuacji nie powinno być użytkowników, którzy podają hasło, a proces uwierzytelniania mógłby być tak prosty, jak za pomocą jednego przycisku logowania. Po jego kliknięciu pojawia się okno wyboru konta, w którym użytkownik może wybrać konto, odblokować ekran, aby przejść weryfikację i się zalogować.

Jednak przejście z uwierzytelniania na hasło na podstawie klucza dostępu może być trudne. Gdy użytkownicy przechodzą na klucze dostępu, niektórzy użytkownicy korzystający z haseł i witryny będą musieli obsługiwać oba te typy użytkowników. Użytkownicy nie powinni zapamiętywać, z których witryn przenieśli się na klucze dostępu, więc proszenie ich o wybranie metody z góry nie zapewni użytkownikom dobrych wrażeń.

Klucze dostępu to również nowa technologia. Wyjaśnienie tych kwestii i dbanie o to, by użytkownicy są mogli z nich wygodnie korzystać, może być wyzwaniem dla witryn. Aby rozwiązać oba problemy, w przypadku autouzupełniania haseł możemy polegać na znanych interfejsach użytkownika.

Interfejs warunkowy

Aby zwiększyć wygodę użytkowników korzystających zarówno z kluczy dostępu, jak i haseł, możesz uwzględniać klucze dostępu w sugestiach autouzupełniania. Nazywa się to warunkowym interfejsem użytkownika i jest częścią standardu WebAuthn.

Gdy tylko użytkownik kliknie pole do wpisania nazwy użytkownika, pojawi się okno z sugestią autouzupełniania, w której wyróżnione będą zapisane klucze dostępu wraz z sugestiami autouzupełniania haseł. Następnie użytkownik może wybrać konto i używać blokady ekranu urządzenia, aby się zalogować.

W ten sposób użytkownicy będą mogli logować się w Twojej witrynie przy użyciu dotychczasowego formularza, tak jakby nic się nie zmieniło. Będzie to jednak miało dodatkowe korzyści w związku z bezpieczeństwem kluczy dostępu (jeśli go ma).

Jak to działa

Do uwierzytelniania za pomocą klucza dostępu służy interfejs WebAuthn API.

4 elementy uwierzytelniania za pomocą klucza dostępu to: użytkownik:

  • Backend: serwer backendu, w którym znajduje się baza danych kont przechowująca klucz publiczny i inne metadane klucza dostępu.
  • Frontend: frontend, który komunikuje się z przeglądarką i wysyła żądania pobierania do backendu.
  • Przeglądarka: przeglądarka użytkownika, która używa Twojego JavaScriptu.
  • Authenticator: mechanizm uwierzytelniający użytkownika, który tworzy i przechowuje klucz dostępu. Może być na tym samym urządzeniu co przeglądarka (np.w Windows Hello) lub na innym urządzeniu, np. telefonie.
Schemat uwierzytelniania klucza dostępu
  1. Gdy tylko użytkownik trafia do frontendu, wysyła od backendu żądanie uwierzytelnienia za pomocą klucza dostępu i wywołuje navigator.credentials.get() w celu zainicjowania uwierzytelniania za pomocą klucza dostępu. Zwraca wartość Promise.
  2. Gdy użytkownik umieści kursor w polu logowania, przeglądarka wyświetli okno autouzupełniania hasła z kluczami dostępu. Jeśli użytkownik wybierze klucz dostępu, pojawi się okno uwierzytelniania.
  3. Gdy użytkownik potwierdzi swoją tożsamość przy użyciu blokady ekranu urządzenia, obietnica zostanie zrealizowana, a dane uwierzytelniające klucza publicznego zostaną zwrócone do frontendu.
  4. Frontend wysyła do backendu dane uwierzytelniające klucza publicznego. Backend weryfikuje podpis pod kątem klucza publicznego dopasowanego konta w bazie danych. Jeśli próba się powiedzie, użytkownik będzie zalogowany.

Wymagania wstępne

Warunkowy interfejs WebAuthn jest publicznie obsługiwany w Safari na urządzeniach z iOS 16, iPadOS 16 i macOS Ventura. Jest też dostępna w Chrome na urządzeniach z Androidem, macOS i Windows 11 (22H2).

Uwierzytelniaj za pomocą klucza dostępu przez autouzupełnianie formularzy

Gdy użytkownik chce się zalogować, możesz wykonać warunkowe wywołanie get WebAuthn, aby wskazać, że w sugestiach autouzupełniania mogą być uwzględniane klucze dostępu. Warunkowe wywołanie interfejsu API navigator.credentials.get() usługi WebAuthn nie wyświetla interfejsu użytkownika i pozostaje oczekujące, dopóki z sugestii autouzupełniania użytkownik nie wybierze konta, na które ma się zalogować. Jeśli użytkownik wybierze klucz dostępu, przeglądarka rozstrzygnie obietnicę za pomocą danych logowania, a nie formularza logowania. Obowiązek zalogowania się na stronie spoczywa na stronie.

Pole do wprowadzania adnotacji w formularzu

W razie potrzeby dodaj atrybut autocomplete do pola nazwy użytkownika input. Dołącz username i webauthn jako jego tokeny, aby umożliwić sugerowanie kluczy dostępu.

<input type="text" name="username" autocomplete="username webauthn" ...>

Wykrywanie funkcji

Przed wywołaniem warunkowego wywołania interfejsu WebAuthn API sprawdź, czy:

  • Przeglądarka obsługuje WebAuthn.
  • Przeglądarka obsługuje interfejs warunkowy WebAuthn.
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
if (window.PublicKeyCredential &&  
    PublicKeyCredential.​​isConditionalMediationAvailable) {  
  // Check if conditional mediation is available.  
  const isCMA = await PublicKeyCredential.​​isConditionalMediationAvailable();  
  if (isCMA) {  
    // Call WebAuthn authentication  
  }  
}  

Pobierz wyzwanie z serwera RP

Pobierz z serwera RP wyzwanie, które jest wymagane do wywołania navigator.credentials.get():

  • challenge: wyzwanie wygenerowane przez serwer w Buforze tablicy. Jest to konieczne, aby zapobiegać atakom metodą powtórzenia. Pamiętaj, aby generować nowe wyzwanie przy każdej próbie logowania i zignorować je po określonym czasie lub wtedy, gdy próba logowania się nie powiedzie. Traktuj go jak token CSRF.
  • allowCredentials: tablica akceptowanych danych uwierzytelniających podczas tego uwierzytelniania. Przekaż pustą tablicę, aby umożliwić użytkownikowi wybranie dostępnego klucza z listy wyświetlanej przez przeglądarkę.
  • userVerification: Wskazuje, czy weryfikacja użytkownika przy użyciu blokady ekranu urządzenia to "required", "preferred" czy "discouraged". Wartość domyślna to "preferred", co oznacza, że mechanizm uwierzytelniania może pominąć weryfikację użytkownika. Ustaw tę wartość na "preferred" lub pomiń tę właściwość.

Wywołaj interfejs WebAuthn API z flagą conditional, aby uwierzytelnić użytkownika

Wywołaj navigator.credentials.get(), aby rozpocząć oczekiwanie na uwierzytelnienie użytkownika.

// To abort a WebAuthn call, instantiate an `AbortController`.
const abortController = new AbortController();

const publicKeyCredentialRequestOptions = {
  // Server generated challenge
  challenge: ****,
  // The same RP ID as used during registration
  rpId: 'example.com',
};

const credential = await navigator.credentials.get({
  publicKey: publicKeyCredentialRequestOptions,
  signal: abortController.signal,
  // Specify 'conditional' to activate conditional UI
  mediation: 'conditional'
});
  • rpId: Identyfikator RP to domena, a witryna może określać swoją domenę lub sufiks dostępny do zarejestrowania. Ta wartość musi być zgodna z identyfikatorem rp.id użytym podczas tworzenia klucza dostępu.

Pamiętaj, by określić właściwość mediation: 'conditional', by żądanie było warunkowe.

Wyślij zwrócone dane uwierzytelniające klucza publicznego do serwera RP

Gdy użytkownik wybierze konto i wyrazi zgodę przy użyciu blokady ekranu urządzenia, obietnica zostanie zrealizowana, a obiekt PublicKeyCredential zostanie zwrócony do frontendu RP.

Obietnica może zostać odrzucona z kilku różnych powodów. Musisz naprawić błędy w zależności od właściwości name obiektu Error:

  • NotAllowedError: użytkownik anulował operację.
  • Inne wyjątki: wystąpiło coś nieoczekiwanego. Przeglądarka wyświetli użytkownikowi okno z błędem.

Obiekt danych logowania klucza publicznego zawiera te właściwości:

  • id: zakodowany w base64url identyfikator uwierzytelnionych danych logowania klucza dostępu.
  • rawId: wersja identyfikatora danych logowania w formacie ArrayBuffer.
  • response.clientDataJSON: obiekt ArrayBuffer z danymi klienta. Zawiera ono informacje takie jak test zabezpieczający oraz źródło, które musi zweryfikować serwer RP.
  • response.authenticatorData: obiekt ArrayBuffer z danymi uwierzytelniającymi. To pole zawiera informacje, np. identyfikator RP.
  • response.signature: tablica Buffer podpisu. Ta wartość jest podstawą danych logowania i musi zostać zweryfikowana na serwerze.
  • response.userHandle: obiekt tablica Buffer zawierający identyfikator użytkownika ustawiony w czasie tworzenia. Tej wartości można użyć zamiast identyfikatora danych logowania, jeśli serwer musi wybrać używane wartości identyfikatora lub jeśli backend nie chce tworzyć indeksu dla identyfikatorów danych logowania.
  • authenticatorAttachment: Zwraca wartość platform, gdy te dane logowania pochodzą z urządzenia lokalnego. W przeciwnym razie cross-platform, zwłaszcza gdy użytkownik logował się przy użyciu telefonu. Jeśli użytkownik musi logować się przy użyciu telefonu, możesz poprosić go o utworzenie klucza dostępu na urządzeniu lokalnym.
  • type: to pole ma zawsze wartość "public-key".

Jeśli do obsługi obiektu danych logowania klucza publicznego na serwerze RP używasz biblioteki, zalecamy wysłanie całego obiektu na serwer po jego częściowym zakodowaniu w base64url.

Sprawdzanie podpisu

Gdy otrzymasz na serwerze dane uwierzytelniające klucza publicznego, przekaż je do biblioteki FIDO w celu przetworzenia obiektu.

Wyszukaj zgodny identyfikator danych logowania za pomocą właściwości id (jeśli chcesz określić konto użytkownika, użyj właściwości userHandle, której wartość user.id została podana podczas tworzenia danych logowania). Sprawdź, czy signature danych logowania można zweryfikować za pomocą zapisanego klucza publicznego. Zalecamy skorzystanie z biblioteki po stronie serwera lub innego rozwiązania zamiast pisania własnego kodu. Biblioteki open source znajdziesz w repozytorium Awesome-webauth na GitHubie.

Gdy dane logowania zostaną zweryfikowane przy użyciu pasującego klucza publicznego, zaloguj użytkownika.

Zasoby