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

Utwórz środowisko logowania, które wykorzystuje klucze dostępu, jednocześnie uwzględniając przy tym istniejących użytkowników haseł.

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

Dlaczego warto korzystać z autouzupełniania formularzy w celu logowania się za pomocą klucza dostępu?

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

W idealnej sytuacji nie powinno być żadnych użytkowników haseł, a proces uwierzytelniania byłby tak prosty, jak przycisk logowania jednokrotnego. Gdy użytkownik kliknie przycisk, pojawi się okno wyboru konta, w którym będzie mógł wybrać konto, odblokować ekran w celu weryfikacji i się zalogować.

Jednak przejście z hasła na uwierzytelnianie oparte na kluczu dostępu może być trudne. Użytkownicy korzystający z kluczy dostępu nadal będą używać haseł, a strony internetowe będą musiały obsługiwać oba te rodzaje użytkowników. Nie należy oczekiwać, że użytkownicy sami będą zapamiętywać, w których witrynach przełączyli się na klucze dostępu, dlatego prośba o wybór sposobu użycia od razu nie będzie dla nich satysfakcjonująca.

Klucze dostępu to również nowa technologia. Wyjaśnienie tych zasad i zapewnienie użytkownikom wygody korzystania z nich może być wyzwaniem dla witryn. Podczas autouzupełniania haseł można polegać na dobrze znanym interfejsie użytkownika.

Interfejs warunkowy

Aby zapewnić użytkownikom wygodne korzystanie zarówno z kluczy dostępu, jak i haseł, możesz uwzględnić klucze dostępu w sugestiach autouzupełniania. Jest to tzw. warunkowy interfejs i jest częścią standardu WebAuthn.

Gdy tylko użytkownik kliknie pole do wpisania nazwy użytkownika, pojawi się okno z sugestiami autouzupełniania, w którym podświetlone są zapisane klucze dostępu i sugestie autouzupełniania haseł. Użytkownik może potem wybrać konto i zalogować się przy użyciu blokady ekranu urządzenia.

Dzięki temu użytkownicy będą mogli logować się w Twojej witrynie za pomocą dotychczasowego formularza, jak gdyby nic się nie zmieniło, z dodatkową zaletą w postaci kluczy dostępu (o ile mają klucze dostępu).

Jak to działa

Do uwierzytelniania za pomocą klucza dostępu używasz interfejsu WebAuthn API.

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

  • Backend: serwer backendu, w którym znajduje się baza danych kont, w której jest przechowywany klucz publiczny i inne metadane dotyczące 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 uruchomi Twój JavaScript.
  • Authenticator: aplikacja uwierzytelniająca użytkownika, która tworzy i przechowuje klucz dostępu. Może to być na tym samym urządzeniu co przeglądarka (np. za pomocą Windows Hello) lub na innym urządzeniu, na przykład na telefonie.
Diagram uwierzytelniania klucza dostępu
  1. Gdy tylko użytkownik trafia do frontendu, wysyła do backendu żądanie uwierzytelnienia za pomocą klucza dostępu i wywołuje navigator.credentials.get(), aby rozpocząć uwierzytelnianie za pomocą klucza dostępu. Spowoduje to zwrócenie Promise.
  2. Gdy użytkownik umieści kursor w polu logowania, przeglądarka wyświetli okno autouzupełniania hasła z kluczami dostępu. Gdy użytkownik wybierze klucz dostępu, pojawi się okno uwierzytelniania.
  3. Gdy użytkownik zweryfikuje swoją tożsamość za pomocą blokady ekranu urządzenia, obietnica zostanie zrealizowana, a frontend zwrócono dane logowania klucza publicznego.
  4. Frontend wysyła do backendu dane logowania klucza publicznego. Backend weryfikuje podpis przy użyciu klucza publicznego dopasowanego konta w bazie danych. W przypadku powodzenia użytkownik jest zalogowany.

Wymagania wstępne

Warunkowy interfejs WebAuthn jest publicznie obsługiwany w Safari na urządzeniach z systemem 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 wywołać warunkowe wywołanie get WebAuthn, aby wskazać, że w sugestiach autouzupełniania mogą być uwzględniane klucze dostępu. Warunkowe wywołanie interfejsu API WebAuthn w usłudze navigator.credentials.get() nie wyświetla interfejsu i pozostaje w stanie oczekiwania, dopóki użytkownik nie wybierze konta, na które będzie się zalogować, korzystając z sugestii autouzupełniania. Jeśli użytkownik wybierze klucz dostępu, przeglądarka zaakceptuje dane logowania, zamiast wypełniać formularz logowania. Wtedy musisz samodzielnie zalogować użytkownika na stronie.

Dodaj adnotację do pola do wprowadzania danych w formularzu

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

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

Wykrywanie cech

Zanim wywołasz warunkowe wywołanie interfejsu WebAuthn API, sprawdź, czy:

  • Przeglądarka obsługuje WebAuthn.
  • Przeglądarka obsługuje warunkowy interfejs 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 wyzwanie z serwera RP, które jest wymagane do wywołania navigator.credentials.get():

  • challenge: wyzwanie zadanie wygenerowane przez serwer w SlateBuffer. Jest to wymagane, aby zapobiec atakom metodą powtórzenia. Wygeneruj nowe zadanie przy każdej próbie logowania i zignoruj je po określonym czasie lub po nieudanej próbie zalogowania się. Potraktuj go jak token CSRF.
  • allowCredentials: tablica z danymi logowania akceptowanymi w przypadku tego uwierzytelniania. Przekaż pustą tablica, aby użytkownik mógł wybrać dostępny klucz dostępu z listy wyświetlanej przez przeglądarkę.
  • userVerification: wskazuje, czy weryfikacja użytkownika za pomocą blokady ekranu urządzenia to "required", "preferred" czy "discouraged". Wartość domyślna to "preferred", co oznacza, że uwierzytelnianie może pominąć weryfikację użytkownika. Ustaw tę wartość na "preferred" lub pomiń tę właściwość.

Wywołaj interfejs WebAuthn API za pomocą flagi conditional w celu uwierzytelnienia użytkownika

Wywołaj navigator.credentials.get(), aby rozpocząć oczekiwanie na uwierzytelnianie 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ślić swoją domenę lub sufiks możliwy do zarejestrowania. Ta wartość musi być zgodna z identyfikatorem rp.id używanym podczas tworzenia klucza dostępu.

Pamiętaj, aby określić mediation: 'conditional', aby żą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 przez zwrócenie obiektu PublicKeyCredential do frontendu RP.

Obietnica może zostać odrzucona z kilku różnych powodów. W zależności od właściwości name obiektu Error musisz rozwiązać te problemy:

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

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

  • id: identyfikator zakodowany w base64url uwierzytelnionego klucza dostępu.
  • rawId: wersja identyfikatora danych logowania w formacie ArrayBuffer.
  • response.clientDataJSON: obiekt tablicaBuffer danych klienta. To pole zawiera informacje takie jak wyzwanie i pochodzenie, które serwer RP będzie musiał zweryfikować.
  • response.authenticatorData: obiekt ArrayBuffer danych uwierzytelniających. To pole zawiera informacje takie jak identyfikator RP.
  • response.signature: element tablicaBuffer podpisu. Ta wartość stanowi rdzeń danych logowania i wymaga weryfikacji na serwerze.
  • response.userHandle: obiekt ArrayBuffer zawierający identyfikator użytkownika ustawiony podczas tworzenia. Tej wartości można użyć zamiast identyfikatora danych logowania, gdy serwer musi wybrać używane wartości identyfikatorów lub gdy backend chce uniknąć tworzenia indeksu dla tych identyfikatorów.
  • authenticatorAttachment: zwraca wartość platform, jeśli dane logowania pochodzą z urządzenia lokalnego. W innym przypadku cross-platform, zwłaszcza gdy użytkownik logował się za pomocą telefonu. Jeśli użytkownik musiał zalogować się przy użyciu telefonu, możesz poprosić go o utworzenie klucza dostępu na urządzeniu lokalnym.
  • type: to pole zawsze jest ustawione na "public-key".

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

Sprawdzanie podpisu

Gdy otrzymasz na serwerze dane uwierzytelniające klucza publicznego, przekaż je do biblioteki FIDO, aby przetworzyć obiekt.

Wyszukaj odpowiedni identyfikator danych logowania za pomocą właściwości id (aby określić konto użytkownika, użyj właściwości userHandle, która jest wartością user.id podaną podczas tworzenia danych logowania). Sprawdź, czy signature certyfikatu można zweryfikować za pomocą zapisanego klucza publicznego. Zamiast pisać własny kod, zalecamy skorzystanie z biblioteki po stronie serwera lub innego rozwiązania. Biblioteki open source znajdziesz w repozytorium niesamowitego Webauth na GitHubie.

Po zweryfikowaniu danych logowania przy użyciu odpowiedniego klucza publicznego zaloguj użytkownika.

Zasoby