Jak stworzyliśmy kartę WebAuthn w Chrome DevTools

Fawaz Mohammad
Fawaz Mohammad
Nina Satragno
Nina Satragno

Interfejs Web Authentication API, znany też jako WebAuthn, umożliwia serwerom rejestrowanie i uwierzytelnianie użytkowników przy użyciu szyfrowania kluczem publicznym zamiast haseł. Dokonuje tego, umożliwiając integrację tych serwerów z silnym uwierzytelnianiem. Uwierzytelnikami mogą być dedykowane urządzenia fizyczne (np. klucze bezpieczeństwa) lub zintegrowane z platformami (np. czytniki linii papilarnych). Więcej informacji o WebAuthn znajdziesz na stronie webauthn.guide.

Problemy deweloperów

Przed tym projektem WebAuthn nie miał obsługi debugowania natywnego w Chrome. Deweloperzy tworzyli aplikację, która używała WebAuth, wymagając dostępu do fizycznych uwierzytelniających. Było to szczególnie trudne z 2 powodów:

  1. Istnieją różne rodzaje uwierzytelniania. Debugowanie szerokiej gamy konfiguracji i możliwości wymagało od dewelopera dostępu do wielu różnych, czasem drogich uwierzytelniających.

  2. Fizyczne uwierzytelnianie jest bezpieczne z założenia. Dlatego sprawdzenie ich stanu jest zwykle niemożliwe.

Aby ułatwić to zadanie, dodaliśmy obsługę debugowania bezpośrednio w Narzędziach deweloperskich w Chrome.

Rozwiązanie: nowa karta WebAuthn

Karta WebAuthn w Narzędziach deweloperskich znacznie ułatwia debugowanie WebAuthn, ponieważ pozwala deweloperom emulować te uwierzytelniacze, dostosowywać ich możliwości i sprawdzać ich stan.

Nowa karta WebAuthn

Implementacja

Dodanie obsługi debugowania do WebAuthn było procesem dwuetapowym.

Proces dwuetapowy

Część 1. Dodawanie domeny WebAuthn do protokołu narzędzi deweloperskich w Chrome

Najpierw wdrożyliśmy nową domenę w protokole Chrome DevTools Protocol (CDP), która łączy się z obsługą komunikującą się z backendem WebAuthn.

CDP łączy interfejs Narzędzi deweloperskich z Chromium. W naszym przypadku wykorzystaliśmy domenę WebAuthn, aby połączyć kartę WebAuthn w Narzędziach deweloperskich z implementacją WebAuthn w Chromium.

Domena WebAuthn umożliwia włączanie i wyłączanie środowiska wirtualnego mechanizmu uwierzytelniającego, co powoduje odłączenie przeglądarki od rzeczywistego mechanizmu Authenticator Discovery i zamiast tego podłączenie mechanizmu wirtualnego.

W domenie udostępniamy też metody, które działają jako cienka warstwa dla istniejących interfejsów Virtual Authenticator i Virtual Discovery, które są częścią implementacji WebAuthn w Chromium. Te metody obejmują dodawanie i usuwanie uwierzytelniania, a także tworzenie, pobieranie i czyszczenie zarejestrowanych danych logowania.

(czytaj kod)

Część 2. Tworzenie karty dla użytkowników

Po drugie, utworzyliśmy kartę dla użytkowników w interfejsie DevTools. Składa się ona z widoku i modelu. Automatycznie wygenerowany agent łączy domenę z kartą.

Chociaż wymagane są 3 elementy, musieliśmy się zająć tylko 2 z nich: modelemwidokiem. Trzeci element – agent – jest generowany automatycznie po dodaniu domeny. Krótko mówiąc, agent to warstwa, która obsługuje wywołania między interfejsem a CDP.

Model

Model to warstwa JavaScriptu, która łączy agenta z widokiem. W naszym przypadku model jest dość prosty. Pobiera ona polecenia z widoku, tworzy żądania w taki sposób, aby były one dostępne dla CDP, a potem wysyła je za pomocą agenta. Te żądania są zwykle jednokierunkowe i nie zawierają żadnych informacji wysyłanych z powrotem do widoku.

Czasami jednak przekazujemy odpowiedź z modelu, aby podać identyfikator dla nowo utworzonego uwierzytelniania lub zwrócić dane logowania zapisane w istniejącym uwierzytelnianiu.

(czytaj kod)

Widok

Nowa karta WebAuthn

Używamy tego widoku, aby udostępnić interfejs użytkownika, który deweloper może znaleźć po uzyskaniu dostępu do DevTools. Tabela zawiera:

  1. Pasek narzędzi do włączania środowiska wirtualnego mechanizmu uwierzytelniającego.
  2. Sekcja dodawania mechanizmów uwierzytelniających.
  3. Sekcja dotycząca utworzonych uwierzytelniających.

(czytaj kod)

Pasek narzędzi do włączania środowiska wirtualnego mechanizmu uwierzytelniającego

pasek narzędzi

Większość interakcji użytkownika dotyczy jednego uwierzytelniania naraz, a nie całej karty, dlatego jedyną funkcją na pasku narzędzi jest włączanie i wyłączanie środowiska wirtualnego.

Dlaczego jest to konieczne? Ważne jest, aby użytkownik musiał wyraźnie przełączyć środowisko, ponieważ powoduje to odłączenie przeglądarki od prawdziwego Authenticatora. Dlatego, gdy jest włączona, podłączone fizyczne uwierzytelniacze, takie jak czytnik linii papilarnych, nie będą rozpoznawane.

Uznaliśmy, że wyraźny przełącznik oznacza większą wygodę użytkowników, zwłaszcza tych, którzy trafiają na kartę WebAuthn, nie spodziewając się, że prawdziwe wykrywanie zostanie wyłączone.

Dodawanie sekcji „Uwierzytelnianie”

Dodawanie sekcji „Uwierzytelnianie”

Po włączeniu środowiska wirtualnego mechanizmu uwierzytelniającego wyświetlamy deweloperowi formularz inline, który umożliwia dodanie wirtualnego mechanizmu uwierzytelniającego. W ramach tego formularza udostępniamy opcje dostosowywania, które umożliwiają użytkownikowi określenie protokołu i metod przesyłania uwierzytelniania, a także określenie, czy uwierzytelnianie ma obsługiwać klucze rezydenta i weryfikację użytkownika.

Gdy użytkownik kliknie Dodaj, te opcje są grupowane i wysyłane do modelu, który tworzy wywołanie w celu utworzenia uwierzytelniania. Po zakończeniu tej operacji interfejs otrzyma odpowiedź, a następnie zmodyfikuje interfejs użytkownika, aby uwzględnić nowo utworzony uwierzytelniacz.

Widok aplikacji Authenticator

Widok aplikacji Authenticator

Za każdym razem, gdy emulowany jest uwierzytelniacz, do widoku dodawana jest sekcja, która go reprezentuje. Każda sekcja uwierzytelniania zawiera nazwę, identyfikator, opcje konfiguracji, przyciski do usuwania uwierzytelniania lub aktywowania go oraz tabelę danych logowania.

Nazwa aplikacji Authenticator

Nazwę uwierzytelniania można dostosować. Domyślnie jest to „Authenticator” połączone z 5 ostatnimi znakami identyfikatora. Pierwotnie nazwa uwierzytelniania była pełnym identyfikatorem i nie można jej było zmienić. Wprowadziliśmy możliwość dostosowania nazw, aby użytkownik mógł nadać nazwę uwierzytelnikowi na podstawie jego możliwości, fizycznego uwierzytelniania, którego ma emulować, lub dowolnego pseudonimu, który jest nieco łatwiejszy do zapamiętania niż identyfikator składający się z 36 znaków.

Tabela danych logowania

Do każdej sekcji dotyczącej uwierzytelniania dodaliśmy tabelę, która zawiera wszystkie dane logowania zarejestrowane przez uwierzytelniacz. W każdym wierszu podajemy informacje o danych logowania, a także przyciski umożliwiające ich usunięcie lub wyeksportowanie.

Obecnie informacje do wypełniania tych tabel zbieramy, wysyłając zapytanie do CDP w celu uzyskania zarejestrowanych danych logowania dla każdego uwierzytelniania. W przyszłości planujemy dodać zdarzenie tworzenia danych logowania.

Przycisk Aktywny

Dodaliśmy też do każdej sekcji dotyczącej uwierzytelniania przycisk opcji Aktywny. Aktywne urządzenie uwierzytelniające będzie jedynym, które będzie nasłuchiwać i rejestrować poświadczenia. Bez tego rejestrowanie danych logowania z użyciem wielu uwierzytelniających nie jest deterministyczne, co byłoby poważną wadą podczas testowania WebAuthn.

Wprowadziliśmy stan aktywny, korzystając z metody SetUserPresence w przypadku uwierzytelniania wirtualnego. Metoda SetUserPresence określa, czy testy obecności użytkownika w przypadku danego uwierzytelniania są udane. Jeśli wyłączymy to ustawienie, uwierzytelniacz nie będzie mógł odsłuchiwać danych logowania. Dlatego, zapewniając, że jest on włączony w przypadku maksymalnie 1 mechanizmu uwierzytelniającego (tego, który jest ustawiony jako aktywny), a wyłączając obecność użytkownika w przypadku wszystkich pozostałych, możemy wymusić deterministyczne działanie.

Podczas dodawania aktywnego przycisku musieliśmy uniknąć warunków wyścigu. Przyjrzyjmy się temu scenariuszowi:

  1. Użytkownik klika przycisk radiowy Aktywny w przypadku uwierzytelniania X, wysyłając do CDP żądanie ustawienia X jako aktywnego. Zaznaczony jest przycisk opcji Aktywne dla X, a wszystkie pozostałe są odznaczone.

  2. Zaraz potem użytkownik klika przycisk radiowy Aktywny w przypadku uwierzytelniania Y, wysyłając do CDP żądanie ustawienia Y jako aktywnego. Opcja Aktywna dla Y jest zaznaczona, a wszystkie pozostałe, w tym dla X, są odznaczone.

  3. Na zapleczu wywołanie do ustawienia Y jako aktywnego zostało wykonane i rozwiązane. Y jest teraz aktywny, a wszystkie inne uwierzytelniacze nie są.

  4. Na zapleczu wywołanie do ustawienia X jako aktywnego zostało wykonane i rozwiązane. X jest teraz aktywny, a wszystkie inne uwierzytelniacze, w tym Y, nie są aktywne.

W wyniku tej operacji X jest aktywnym mechanizmem uwierzytelniającym. Przycisk Aktywna dla X nie jest wybrany. Y nie jest aktywnym mechanizmem uwierzytelniającym. Przycisk opcji Aktywna jest wybrany dla Y. Istnieje rozbieżność między front-endem a rzeczywistym stanem uwierzytelniania. To oczywiście problem.

Nasze rozwiązanie: ustanowienie pseudo dwukierunkowej komunikacji między przyciskami opcji a aktywnym mechanizmem uwierzytelniania. Po pierwsze, w widoku utrzymujemy zmienną activeId, aby śledzić identyfikator aktualnie aktywnego uwierzytelniania. Następnie czekamy na wywołanie, które skonfiguruje aktywny mechanizm uwierzytelniający, a potem ustawiamy activeId na identyfikator tego mechanizmu. Na koniec przechodzimy przez wszystkie sekcje uwierzytelniania. Jeśli identyfikator tej sekcji jest równy activeId, ustawiamy przycisk jako wybrany. W przeciwnym razie przycisk jest nieaktywny.

Wygląda to tak:


 async _setActiveAuthenticator(authenticatorId) {
   await this._clearActiveAuthenticator();
   await this._model.setAutomaticPresenceSimulation(authenticatorId, true);
   this._activeId = authenticatorId;
   this._updateActiveButtons();
 }
 
 _updateActiveButtons() {
   const authenticators = this._authenticatorsView.getElementsByClassName('authenticator-section');
   Array.from(authenticators).forEach(authenticator => {
     authenticator.querySelector('input.dt-radio-button').checked =
         authenticator.getAttribute('data-authenticator-id') === this._activeId;
   });
 }
 
 async _clearActiveAuthenticator() {
   if (this._activeId) {
     await this._model.setAutomaticPresenceSimulation(this._activeId, false);
   }
   this._activeId = null;
 }

Dane na temat wykorzystania

Chcieliśmy śledzić korzystanie z tej funkcji. Początkowo pojawiły się 2 opcje.

  1. Zlicza każdą próbę otwarcia karty WebAuthn w Narzędziach deweloperskich. Ta opcja może prowadzić do zawyżenia liczby wyświetleń, ponieważ ktoś może otworzyć kartę, ale jej nie używać.

  2. Śledź, ile razy na pasku narzędzi zostało zaznaczone pole wyboru „Włącz środowisko wirtualnego mechanizmu uwierzytelniającego”. Ta opcja miała też problem z przeliczaniem, ponieważ niektórzy użytkownicy mogli włączać i wyłączać środowisko wielokrotnie w ramach tej samej sesji.

Ostatecznie zdecydowaliśmy się na tę drugą opcję, ale ograniczyliśmy zliczanie, sprawdzając, czy środowisko zostało już włączone w ramach sesji. W związku z tym zwiększymy tylko liczbę o 1, niezależnie od tego, ile razy deweloper przełączył środowisko. Dzieje się tak, ponieważ za każdym razem, gdy otwierasz kartę, tworzona jest nowa sesja, która zeruje sprawdzanie i umożliwia ponowne zwiększenie wartości danych.

Podsumowanie

Dziękujemy za przeczytanie tego artykułu. Jeśli masz sugestie dotyczące ulepszenia karty WebAuthn, prosimy o poinformowanie nas o tym, przesyłając zgłaszanie błędu.

Jeśli chcesz dowiedzieć się więcej o WebAuthn, zapoznaj się z tymi materiałami:

Pobieranie kanałów podglądu

Rozważ użycie przeglądarki Chrome Canary, Dev lub Beta jako domyślnej przeglądarki deweloperskiej. Te kanały wersji wstępnej zapewniają dostęp do najnowszych funkcji DevTools, umożliwiają testowanie najnowocześniejszych interfejsów API platformy internetowej i pomagają znaleźć problemy w witrynie, zanim zrobią to użytkownicy.

Kontakt z zespołem Narzędzi deweloperskich w Chrome

Aby omówić nowe funkcje, aktualizacje lub inne kwestie związane z Narzędziami deweloperskimi, skorzystaj z tych opcji.