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.
- 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óceniePromise
. - 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.
- Gdy użytkownik zweryfikuje swoją tożsamość za pomocą blokady ekranu urządzenia, obietnica zostanie zrealizowana, a frontend zwrócono dane logowania klucza publicznego.
- 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.
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 w interfejsie
PublicKeyCredential
.
- Przeglądarka obsługuje warunkowy interfejs WebAuthn za pomocą interfejsu
PublicKeyCredenital.isConditionalMediationAvailable()
.
// 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 przypadkucross-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 we 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.
Postępuj zgodnie ze szczegółowymi instrukcjami dotyczącymi uwierzytelniania kluczy dostępu po stronie serwera