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

Utwórz funkcję logowania, która wykorzystuje klucze dostępu, a jednocześnie uwzględnia użytkowników, którzy korzystają z haseł.

Z tego przewodnika dowiesz się, jak używać funkcji automatycznego wypełniania formularzy, aby umożliwić użytkownikom logowanie się za pomocą kluczy dostępu i haseł. Korzystanie z automatycznego wypełniania formularzy umożliwia prowadzenie jednolitego procesu logowania, co upraszcza przejście z haseł na bezpieczniejszą i przyjaźniejszą dla użytkownika metodę uwierzytelniania za pomocą kluczy dostępu.

Dowiedz się, jak wdrożyć interfejs użytkownika warunkowego WebAuthn, aby obsługiwać użytkowników korzystających z kluczy dostępu i haseł z minimalnym wysiłkiem w dotychczasowych formularzach logowania.

Dlaczego warto używać Autouzupełniania formularzy do logowania się przy użyciu klucza dostępu?

Klucze dostępu umożliwiają użytkownikom logowanie się na stronach internetowych za pomocą odcisku palca, twarzy lub kodu PIN urządzenia.

Jeśli wszyscy użytkownicy mieliby klucze dostępu, proces uwierzytelniania mógłby polegać na jednym kliknięciu przycisku logowania. Po jego kliknięciu użytkownik mógłby bezpośrednio zweryfikować konto za pomocą blokady ekranu i zalogować się.

Przejście z haseł na klucze dostępu wiąże się jednak z pewnymi wyzwaniami. W tym czasie witryny muszą obsługiwać zarówno użytkowników logujących się za pomocą hasła, jak i klucza dostępu. Oczekiwanie od użytkowników, że będą pamiętać, które witryny używają kluczy dostępu, i proszenie ich o wybranie metody logowania z góry, powoduje nieprzyjemne wrażenia użytkowników.

Klucze dostępu to też nowa technologia, której jasne wyjaśnienie może być trudne. Użycie znanego interfejsu autouzupełniania pomaga rozwiązać problem przejścia na nową funkcję i zapewnić użytkownikom znajomość.

Korzystanie z interfejsu warunkowego

Aby skutecznie obsługiwać użytkowników korzystających z kluczy dostępu i haseł, uwzględnij klucze dostępu w sugestiach autouzupełniania formularza. To podejście wykorzystuje interfejs użytkownika warunkowego, który jest funkcją standardu WebAuthn.

Przykład wyboru klucza dostępu za pomocą autouzupełniania formularza

Gdy użytkownik skupi się na polu nazwy użytkownika, pojawi się okno autouzupełniania z zapisanymi kluczami dostępu i hasłami. Użytkownik może wybrać klucz dostępu lub hasło i zalogować się, używając blokady ekranu urządzenia, jeśli wybierze klucz dostępu.

Dzięki temu użytkownicy mogą logować się na Twojej stronie za pomocą dotychczasowego formularza logowania, ale z dodatkowym zabezpieczeniem w postaci kluczy dostępu, jeśli je mają.

Jak działa uwierzytelnianie za pomocą klucza dostępu

Aby uwierzytelnić się za pomocą klucza dostępu, użyj interfejsu WebAuthn API.

Cztery elementy procesu uwierzytelniania za pomocą klucza dostępu:

  • Backend: przechowuje szczegóły konta użytkownika, w tym klucz publiczny.
  • Frontend: komunikuje się z przeglądarką i pobiera z backendu niezbędne dane.
  • Przeglądarka: uruchamia kod JavaScript i współdziała z interfejsem WebAuthn API.
  • Dostawca kluczy dostępu: tworzy i przechowuje klucz dostępu. Jest to zwykle menedżer haseł, np. Menedżer haseł Google, lub klucz bezpieczeństwa.
Proces uwierzytelniania za pomocą klucza dostępu, pokazujący interakcję między front-endem, back-endem, przeglądarką i dostawcą klucza dostępu.
Pełny proces uwierzytelniania za pomocą klucza dostępu

Proces uwierzytelniania za pomocą kluczy dostępu przebiega w taki sposób:

  1. Użytkownik odwiedza stronę logowania, a frontend wysyła do back-endu prośbę o wyzwanie uwierzytelniania.
  2. Backend generuje i zwraca wyzwanie WebAuthn powiązane z kontem użytkownika.
  3. Frontend wywołuje navigator.credentials.get() z wyzwaniem, aby zainicjować uwierzytelnianie za pomocą przeglądarki.
  4. Przeglądarka, współpracując z dostawcą klucza dostępu, prosi użytkownika o wybranie klucza dostępu (często za pomocą okna autouzupełniania wywołanego przez skupienie na polu logowania) i potwierdza jego tożsamość, korzystając z blokady ekranu lub danych biometrycznych.
  5. Po zweryfikowaniu użytkownika dostawca klucza dostępu podpisuje wyzwanie, a przeglądarka zwraca uzyskane w ten sposób dane uwierzytelniające z kluczem publicznym (w tym podpisem) do front-endu.
  6. Frontend wysyła te dane logowania do backendu.
  7. Serwer weryfikuje podpis danych logowania na podstawie przechowywanego klucza publicznego użytkownika. Jeśli weryfikacja się powiedzie, backend zaloguje użytkownika.

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

Aby zainicjować uwierzytelnianie za pomocą klucza dostępu przy użyciu autouzupełniania formularzy, wykonaj wywołanie WebAuthn get warunkowe, gdy wczytuje się strona logowania. Ten telefon do navigator.credentials.get() zawiera opcję mediation: 'conditional'.
Żądanie warunkowe do interfejsu API WebAuthn nie wyświetla interfejsu użytkownika od razu.navigator.credentials.get() Zamiast tego czeka w stanie oczekującym, aż użytkownik wejdzie w interakcję z prośbą o wypełnienie pola nazwy użytkownika. Jeśli użytkownik wybierze klucz dostępu, przeglądarka zrealizuje oczekujące obietnice za pomocą danych logowania, aby zalogować użytkownika, pomijając tradycyjne przesyłanie formularzy. Jeśli użytkownik zamiast tego wybierze hasło, obietnica nie zostanie spełniona i kontynuowany będzie standardowy proces logowania za pomocą hasła. W takim przypadku odpowiedzialność za zalogowanie użytkownika spoczywa na stronie.

Dodawanie adnotacji do pól formularza

Aby włączyć autouzupełnianie kluczy dostępu, dodaj atrybut autocomplete do pola formularza input „Nazwa użytkownika”. Uwzględnij wartości usernamewebauthn jako wartości rozdzielone spacjami.

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

Dodanie autofocus do tego pola automatycznie uruchamia prompt automatycznego wypełniania po załadowaniu strony, wyświetlając dostępne hasła i klucze dostępu.

Wykrywanie funkcji

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

  • Przeglądarka obsługuje WebAuthn z PublicKeyCredential.

Browser Support

  • Chrome: 67.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

Source

Browser Support

  • Chrome: 108.
  • Edge: 108.
  • Firefox: 119.
  • Safari: 16.

Source

Z poniższego fragmentu kodu dowiesz się, jak sprawdzić, czy przeglądarka obsługuje te funkcje:

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

Pobieranie informacji z backendu

Backend musi udostępnić front-endowi kilka opcji umożliwiających inicjowanie wywołania navigator.credentials.get(). Te opcje są zwykle pobierane jako obiekty JSON z punktu końcowego na serwerze.

Najważniejsze właściwości obiektu opcji to:

  • challenge: wyzwanie wygenerowane przez serwer w ArrayBuffer (zwykle zakodowane w formacie Base64URL do przesyłania w formacie JSON). Jest to niezbędne, aby zapobiec atakom typu replay. Twój serwer musi generować nowe wyzwanie dla każdej próby logowania i unieważnia go po krótkim czasie lub w przypadku niepowodzenia próby.
  • allowCredentials: tablica opisów danych logowania. Przekaż pustą tablicę. Spowoduje to wyświetlenie przez przeglądarkę wszystkich danych logowania dla określonego rpId.
  • userVerification: określa preferowaną metodę weryfikacji użytkownika, np. wymaganie blokady ekranu urządzenia. Wartością domyślną i zalecaną jest "preferred". Możliwe wartości:

    • "required": weryfikacja użytkownika musi być przeprowadzona przez aplikację uwierzytelniającą (np. za pomocą kodu PIN lub danych biometrycznych). Operacja się nie powiedzie, jeśli nie uda się przeprowadzić weryfikacji.
    • "preferred": uwierzytelniacz próbuje zweryfikować użytkownika, ale operacja może się powieść bez tego.
    • "discouraged": w miarę możliwości aplikacja uwierzytelniająca powinna unikać weryfikacji użytkownika.
  • rpId: identyfikator strony trzeciej, zwykle domena witryny (np. example.com). Ta wartość musi dokładnie odpowiadać wartości rp.id użytej podczas tworzenia danych logowania do klucza dostępu.

Twój serwer powinien utworzyć ten obiekt opcji. Wartości ArrayBuffer (np. challenge) muszą być zapisane w formacie Base64URL w celu przesyłania w formacie JSON. Po przeanalizowaniu danych w formacie JSON na stronie front-end, użyj funkcji PublicKeyCredential.parseRequestOptionsFromJSON(), aby przekonwertować obiekt (w tym dekodowanie ciągów znaków Base64URL) do formatu wymaganego przez funkcję navigator.credentials.get().

Ten fragment kodu pokazuje, jak pobierać i dekodować informacje potrzebne do uwierzytelnienia za pomocą klucza dostępu.

// Fetch an encoded PubicKeyCredentialRequestOptions from the server.
const _options = await fetch('/webauthn/signinRequest');

// Deserialize and decode the PublicKeyCredentialRequestOptions.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseRequestOptionsFromJSON(decoded_options);
...

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

Gdy obiekt publicKeyCredentialRequestOptions (w przykładowym kodzie poniżej nazywany options) jest gotowy, wywołaj funkcję navigator.credentials.get(), aby zainicjować uwierzytelnianie za pomocą klucza dostępu warunkowego.

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

// Invoke WebAuthn to authenticate with a passkey.
const credential = await navigator.credentials.get({
  publicKey: options,
  signal: abortController.signal,
  // Specify 'conditional' to activate conditional UI
  mediation: 'conditional'
});

Najważniejsze parametry tego wywołania:

  • publicKey: musi to być obiekt publicKeyCredentialRequestOptions (w tym przykładzie o nazwie options), który został pobrany z serwera i przetworzony w poprzednim kroku.
  • signal: przekazanie sygnału AbortController (np. abortController.signal) umożliwia anulowanie prośby get() za pomocą kodu. Jest to przydatne, gdy chcesz wywołać inny wywołanie WebAuthn.
  • mediation: 'conditional': to kluczowa flaga, która warunkuje wywołanie WebAuthn. Informuje przeglądarkę, aby zaczekała na interakcję użytkownika z prośbą o autouzupełnianie zamiast natychmiastowego wyświetlenia wyskakującego okienka.

Prześlij zwrócone przez niego poświadczenia tożsamości klucza publicznego do serwera RP.

Jeśli użytkownik wybierze klucz dostępu i potwierdzi swoją tożsamość (na przykład za pomocą blokady ekranu urządzenia), navigator.credentials.get()obiecanie zostanie spełnione. Zwraca on PublicKeyCredential obiekt do front-endu.

Obietnice mogą zostać odrzucone z kilku powodów. Te błędy należy obsługiwać w kodzie, sprawdzając właściwość name obiektu Error:

  • NotAllowedError: operacja została anulowana przez użytkownika lub nie wybrano klucza dostępu.
  • AbortError: operacja została przerwana, prawdopodobnie przez Twój kod korzystający z funkcji AbortController.
  • Inne wyjątki: wystąpił nieoczekiwany błąd. Przeglądarka zwykle wyświetla użytkownikowi okno błędu.

Obiekt PublicKeyCredential zawiera kilka właściwości. Kluczowe właściwości istotne dla uwierzytelniania:

  • id: identyfikator zaszyfrowany w formacie base64url uwierzytelnionego klucza dostępu.
  • rawId: identyfikator danych logowania w postaci tablicy ArrayBuffer.
  • response.clientDataJSON: ArrayBuffer danych klienta. Pole zawiera informacje takie jak wyzwanie i pochodzenie, które serwer musi zweryfikować.
  • response.authenticatorData: ArrayBuffer danych uwierzytelniającego. To pole zawiera informacje takie jak identyfikator RP.
  • response.signature: ArrayBuffer zawierający podpis. Ta wartość jest podstawą danych logowania, a Twój serwer musi zweryfikować ten podpis, używając przechowywanego klucza publicznego tych danych .
  • response.userHandle: ArrayBuffer zawierający identyfikator użytkownika podany podczas rejestracji klucza dostępu.
  • authenticatorAttachment: Wskazuje, czy uwierzytelniacz jest częścią urządzenia klienta (platform) czy zewnętrzny (cross-platform). Jeśli użytkownik zaloguje się za pomocą telefonu, może wystąpić załącznik cross-platform. W takich przypadkach możesz poprosić użytkownika o utworzenie klucza dostępu na bieżącym urządzeniu, aby ułatwić mu korzystanie z aplikacji w przyszłości.
  • type: to pole ma zawsze wartość "public-key".

Aby wysłać obiekt PublicKeyCredential do backendu, najpierw wywołaj metodę .toJSON(). Ta metoda tworzy wersję danych logowania, którą można zserializować w formacie JSON. Umożliwia ona prawidłowe przekształcanie właściwości ArrayBuffer (takich jak rawId, clientDataJSON, authenticatorData, signature i userHandle) w ciągi znaków zakodowane w formacie Base64URL. Następnie użyj funkcji JSON.stringify(), aby przekonwertować ten obiekt na ciąg znaków i prześlij go w ciele żądania do serwera.

...
// Encode and serialize the PublicKeyCredential.
const _result = credential.toJSON();
const result = JSON.stringify(_result);

// Encode and send the credential to the server for verification.  
const response = await fetch('/webauthn/signinResponse', {
  method: 'post',
  credentials: 'same-origin',
  body: result
});

Weryfikacja podpisu

Gdy serwer zaplecza otrzyma dane logowania z kluczem publicznym, musi zweryfikować ich autentyczność. Obejmuje to:

  1. parsowanie danych logowania;
  2. wyszukiwanie przechowywanego klucza publicznego powiązanego z id danych logowania.
  3. Weryfikacja otrzymanego signature za pomocą zapisanego klucza publicznego.
  4. weryfikowania innych danych, takich jak wyzwanie i początek.

Zalecamy korzystanie z biblioteki FIDO/WebAuthn po stronie serwera, aby bezpiecznie wykonywać te operacje kryptograficzne. Biblioteki open source znajdziesz w repozytorium GitHub awesome-webauthn.

Jeśli podpis i wszystkie inne oświadczenia są prawidłowe, serwer może zalogować użytkownika. Szczegółowe informacje o weryfikacji po stronie serwera znajdziesz w artykule Uwierzytelnianie za pomocą klucza dostępu po stronie serwera.

sygnał, że na zapleczu nie znaleziono pasujących danych logowania;

Jeśli serwer zaplecza nie może znaleźć danych logowania z pasującym identyfikatorem, użytkownik mógł wcześniej usunąć ten klucz dostępu z Twojego serwera, ale nie z serwera dostawcy kluczy dostępu. To niezgodność może wprowadzać użytkowników w błąd, jeśli dostawca kluczy dostępu będzie nadal sugerować klucz, który nie działa już w Twojej witrynie. Aby to poprawić, prześlij dostawcy kluczy dostępu sygnał, aby usunął klucze dostępu bez właściciela.

Aby poinformować dostawcę klucza dostępu, że określone dane logowania zostały usunięte lub nie istnieją, możesz użyć metody PublicKeyCredential.signalUnknownCredential(), która jest częścią interfejsu Webauthn Signal API. Wywołaj tę stałą metodę po stronie klienta, jeśli Twój serwer wskazuje (na przykład za pomocą określonego kodu stanu HTTP, np. 404), że podany identyfikator danych logowania jest nieznany. W przypadku tej metody podaj identyfikator grupy objętej ograniczeniami i identyfikator nieznanych danych logowania. Dostawca klucza dostępu, jeśli obsługuje sygnał, powinien usunąć klucz dostępu.

// Detect authentication failure due to lack of the credential
if (response.status === 404) {
  // Feature detection
  if (PublicKeyCredential.signalUnknownCredential) {
    await PublicKeyCredential.signalUnknownCredential({
      rpId: "example.com",
      credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
    });
  } else {
    // Encourage the user to delete the passkey from the password manager nevertheless.
    ...
  }
}

Po uwierzytelnieniu

W zależności od tego, jak użytkownik się zalogował, zalecamy stosowanie różnych procesów.

Jeśli użytkownik zalogował się bez klucza dostępu

Jeśli użytkownik zalogował się na Twoją witrynę bez klucza dostępu, może nie mieć zarejestrowanego klucza dostępu dla tego konta lub na bieżącym urządzeniu. To odpowiedni moment, aby zachęcić użytkowników do tworzenia kluczy dostępu. Rozważ te podejścia:

  • Przekształcanie haseł w klucze: użyj warunkowego tworzenia, czyli funkcji WebAuthn, która pozwala przeglądarce automatycznie utworzyć klucz dostępu dla użytkownika po pomyślnym zalogowaniu się za pomocą hasła. Może to znacznie ułatwić stosowanie kluczy dostępu, upraszczając proces ich tworzenia. Dowiedz się, jak to działa i jak to zaimplementować, w artykule Pomaganie użytkownikom w łatwiejszym korzystaniu z kluczy dostępu.
  • Ręczne wyświetlanie prośby o utworzenie klucza dostępu: zachęć użytkowników do utworzenia klucza dostępu. Może to być skuteczne, gdy użytkownik przejdzie bardziej skomplikowany proces logowania, np. uwierzytelnianie wielopoziomowe (MFA). Unikaj jednak nadmiernych podpowiedzi, które mogą przeszkadzać użytkownikom.

Aby dowiedzieć się, jak zachęcić użytkowników do utworzenia klucza dostępu i poznać inne dobre praktyki, zapoznaj się z przykładami w sekcji Komunikowanie użytkownikom informacji o kluczach dostępu.

Jeśli użytkownik zalogował się za pomocą klucza dostępu

Gdy użytkownik zaloguje się za pomocą klucza dostępu, masz kilka możliwości dalszego ulepszania jego wrażeń i utrzymania spójności konta.

Zachęcanie do utworzenia nowego klucza dostępu po uwierzytelnieniu na wielu urządzeniach

Jeśli użytkownik zaloguje się za pomocą klucza dostępu za pomocą mechanizmu obsługiwanego na wielu urządzeniach (np. zeskanuje kod QR za pomocą telefonu), klucz dostępu może nie być przechowywany lokalnie na urządzeniu, na którym użytkownik się loguje. Może się tak zdarzyć, gdy:

  • Użytkownik ma klucz dostępu, ale od dostawcy, który nie obsługuje logowania w systemie operacyjnym lub przeglądarce.
  • Użytkownik stracił dostęp do dostawcy kluczy na urządzeniu, na którym się loguje, ale klucz jest nadal dostępny na innym urządzeniu.

W takim przypadku możesz poprosić użytkownika o utworzenie nowego klucza dostępu na bieżącym urządzeniu. Dzięki temu nie będzie musiał powtarzać procesu logowania na wielu urządzeniach w przyszłości. Aby sprawdzić, czy użytkownik zalogował się za pomocą klucza dostępu na wielu urządzeniach, sprawdź właściwość authenticatorAttachment danych uwierzytelniających. Jeśli jego wartość to "cross-platform", oznacza to uwierzytelnianie na wielu urządzeniach. Jeśli tak, wyjaśnij, dlaczego warto utworzyć nowy klucz dostępu, i przejdź z użytkownikiem przez proces tworzenia.

Synchronizacja szczegółów klucza dostępu z usługodawcą za pomocą sygnałów

Aby zapewnić spójność i większy komfort użytkowników, po stronie Użytkownika (RP) można użyć interfejsu WebAuthn Signals API do przekazywania dostawcy klucza dostępu informacji o danych logowania i użytkownikach.

Aby na przykład utrzymać listę kluczy użytkownika w porządku, dostawca kluczy powinien zsynchronizować dane logowania na zapleczu. Możesz poinformować dostawców kluczy, że klucz już nie istnieje, aby mogli usunąć niepotrzebne klucze.

Podobnie możesz sygnalizować, jeśli użytkownik zaktualizuje swoją nazwę użytkownika lub nazwę wyświetlaną w Twojej usłudze, aby informacje wyświetlane przez dostawcę klucza dostępu (np. w oknach wyboru konta) były aktualne.

Więcej informacji o sprawdzonych metodach utrzymywania spójności kluczy dostępu znajdziesz w artykule Utrzymywanie spójności kluczy dostępu z danymi logowania na serwerze za pomocą interfejsu Signal API.

Nie pytaj o drugi składnik

Klucze dostępu zapewniają solidną, wbudowaną ochronę przed powszechnymi zagrożeniami, takimi jak phishing. Dlatego drugi czynnik uwierzytelniania nie zwiększa znacząco bezpieczeństwa. Zamiast tego tworzy niepotrzebny krok dla użytkowników podczas logowania.

Lista kontrolna

  • Zezwalanie użytkownikom na logowanie się za pomocą klucza dostępu przy użyciu autouzupełniania formularzy.
  • sygnał, gdy na zapleczu nie znaleziono odpowiednich danych logowania;
  • wyświetlać użytkownikom prośbę o ręczne utworzenie klucza dostępu, jeśli nie został on jeszcze utworzony po zalogowaniu się.
  • Automatyczne tworzenie klucza dostępu (tworzenie warunkowe) po zalogowaniu się użytkownika za pomocą hasła (i drugiego czynnika).
  • wyświetlić prośbę o utworzenie lokalnego klucza dostępu, jeśli użytkownik zalogował się za pomocą klucza dostępu na różnych urządzeniach.
  • Po zalogowaniu się lub po wprowadzeniu zmian przesyła do dostawcy listę dostępnych kluczy dostępu i zaktualizowanych danych użytkownika (nazwa użytkownika i nazwa wyświetlana).

Zasoby