spinny:~/writing $ vim passkeys-webauthn-passwordless-authentication.md
1~2Hasła to jedna z tych rzeczy, które znormalizowaliśmy tylko dlatego, że żyjemy z nimi od lat. Użytkownicy o nich zapominają, wykorzystują je ponownie, zapisują tam, gdzie nie powinni. Zespoły muszą zarządzać resetowaniem, zasadami, skrótami, wyciekami, phishingiem i wsparciem.3~4passkey nie czyni uwierzytelnienia doskonałym, ale usuwa ogromny problem: serwer nie musi już zachowywać tajemnicy udostępnianej użytkownikowi.5~6## Co się naprawdę dzieje7~8passkey to referencja oparta na WebAuthn. Gdy użytkownik go utworzy, urządzenie generuje parę kluczy:9~10- klucz prywatny, który pozostaje na urządzeniu lub w menedżerze haseł;11- klucz publiczny, który serwer może zapisać.12~13Podczas logowania serwer nie pyta "podaj mi hasło". Wyślij losowe wyzwanie. Urządzenie podpisuje go kluczem prywatnym. Serwer weryfikuje podpis kluczem publicznym.14~15To właśnie jest fajne: jeśli baza danych zostanie skradziona, nie będzie w niej żadnych haseł, które można by złamać. A jeśli użytkownik trafi na fałszywą domenę, passkey nie będzie ważne dla tej domeny. To nie tylko wygoda, to konkretna ochrona przed phishingiem.16~17## Przeglądarka działa jak pomost18~19W przeglądarce dwa główne API to:20~21- `navigator.credentials.create()`, aby utworzyć passkey;22- `navigator.credentials.get()`, aby użyć go podczas logowania.23~24Ale najważniejsza logika leży na serwerze. Serwer musi wygenerować wyzwanie, zapisać je tymczasowo, zweryfikować odpowiedź, sprawdzić źródło i Relying Party ID, a następnie utworzyć sesję.25~26Część klienta powinna być prawie nudna:27~28```typescript29const options = await fetch('/api/passkeys/login/options').then((r) => r.json());30~31const credential = await navigator.credentials.get({32 publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options),33});34~35await fetch('/api/passkeys/login/verify', {36 method: 'POST',37 headers: { 'Content-Type': 'application/json' },38 body: JSON.stringify(credential?.toJSON()),39});40```41~42Jeśli zauważysz, że ręcznie wdrażasz szyfrowanie WebAuthn, przestań. Użyj solidnej biblioteki po stronie serwera. Błędy tutaj nie są „słodkimi błędami”, są to luki w uwierzytelnianiu.43~44## Co zapisać w bazie danych45~46Nie ma potrzeby ratowania połowy świata. Zwykle wystarczy:47~48- Identyfikator referencji;49- klucz publiczny;50- podłączony użytkownik;51- dowolny licznik weryfikacyjny lub metadane;52- transporty, jeśli są przydatne dla UX;53- nazwa wybrana przez użytkownika;54- data utworzenia i ostatniego użycia.55~56Minimalna tabela może wyglądać następująco:57~58```sql59create table passkey_credentials (60 id uuid primary key default gen_random_uuid(),61 user_id uuid not null references users(id),62 credential_id text not null unique,63 public_key text not null,64 name text,65 created_at timestamptz not null default now(),66 last_used_at timestamptz67);68```69~70Następnie dodałbym logi audytu i powiadomienia: jeśli ktoś utworzy nowe passkey na moim koncie, chcę o tym wiedzieć.71~72## UX jest ważniejszy niż demo73~74Demo passkey jest zawsze piękne: klikasz, Face ID i zaczynasz. Rzeczywisty produkt jest bardziej skomplikowany.75~76Ktoś zmienia telefon. Ktoś korzysta z zablokowanego komputera firmowego. Niektórzy ludzie nie rozumieją, dlaczego przeglądarka sugeruje passkey. Ktoś traci dostęp do swojego urządzenia.77~78Dlatego nie zaczynałbym od „od dzisiaj koniec z hasłami dla wszystkich”. Zacząłbym tak:79~801. passkey opcjonalne dla użytkowników wewnętrznych;812. sugestia utworzenia go po udanym logowaniu;823. strona konta do zmiany nazwy i usunięcia passkey;834. wyraźne wycofanie;845. stopniowe wdrażanie w głównym loginie.85~86Tekst w interfejsie powinien być prosty. „Użyj ekranu blokady swojego urządzenia” jest lepsze niż „uwierzytelnij się za pomocą danych uwierzytelniających rezydenta FIDO2”.87~88## Błędy, których chciałbym uniknąć89~90Nie generuj wyzwań dla klienta. Wyzwanie tworzone jest na serwerze i należy je zweryfikować tylko raz.91~92Nie ufaj tylko identyfikatorowi danych uwierzytelniających. Musisz zweryfikować podpis, wyzwanie, pochodzenie i Relying Party ID.93~94Nie usuwaj kopii zapasowych, zanim nie uzyskasz dobrego przepływu odzyskiwania. Bez hasła nie musi oznaczać, że „jeśli zgubisz telefon, przepadniesz na zawsze”.95~96Nie traktuj passkey jako przycisku czysto frontendowego. Ukrywanie przycisku nie zapewnia bezpieczeństwa: prawdziwa weryfikacja odbywa się po stronie serwera.97~98## Passkey-pierwszy czy passkey-przyjazny?99~100W przypadku nowego produktu możesz najpierw pomyśleć o passkey. W przypadku istniejącej aplikacji wolę przyjazną passkey: dodaj passkey jako zalecaną metodę, mierz sukcesy i problemy, a następnie spokojnie zmniejsz wagę hasła.101~102Idealna migracja nie jest odczuwalna. Użytkownik odkrywa, że logowanie jest łatwiejsze, a nie, że firma zmieniła protokół uwierzytelniania.103~104## Wniosek105~106passkey są interesujące, ponieważ poprawiają jednocześnie bezpieczeństwo i UX, co jest rzadkością. To nie jest magiczna różdżka: odzyskiwanie, kompatybilność, wsparcie i wdrożenie muszą zostać dobrze zaprojektowane.107~108Ale podstawowa zmiana jest silna. Przestań prosić użytkowników o wymyślanie i chronienie tajemnic. Pozwalasz urządzeniu podpisać dowód kryptograficzny powiązany z Twoją domeną. Mniej pamięci ludzkiej, mniej phishingu, mniej resetowania haseł. Powiedziałbym, że warto je traktować poważnie.109~110## Źródła111~112- [MDN: Passkeys](https://developer.mozilla.org/en-US/docs/Web/Security/Authentication/Passkeys)113- [MDN: Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)114- [W3C: Web Authentication](https://www.w3.org/TR/webauthn-3/)115- [passkeys.dev](https://passkeys.dev/)116~
NORMAL · passkeys-webauthn-passwordless-authentication.md [readonly]116 lines · :q to close