Passkeys – možná jste o nich již slyšeli, možná netušíte co jsou. Představím vám, co jsou zač, jak díky nim významně usnadnit ověření uživatelů a zároveň zlepšit bezpečnost nejen autentizace webové aplikace, ale i např. jak snížit SMS OTP náklady. Ukážeme si, jak to celé funguje zvenku i zevnitř. Čeká na vás plně funkční demo s kompletním zdrojovým kódem. Podíváme se, kam se passkeys vyvíjí a co budou brzy umět nového. To celé doplním o vlastní zkušenosti ve snaze vystihnout to podstatné. Pořádný šálek kávy rozhodně přijde vhod, tak tedy vzhůru na to!
Obsah
- Kolik vašich hesel bylo prolomeno?
- Co jsou tedy passkeys?
- Bezpečnostní rizika & soukromí uživatelů
- Stojí za to jít do toho?
Kolik vašich hesel bylo prolomeno?
Zkusme se alespoň odpovědi přiblížit. Moje emailová adresa se dle služby haveibeenpwnded.com nachází ve 24 únicích dat. V mnoha z nich společně s heslem a dalšími citlivými daty. Zlobit se na nedokonalou implementaci dané služby můžeme, ale svět bezpečnosti je proměnlivý a co platilo za bezpečné před pár lety, dnes může sloužit jako falešná jistota bezpečí. Je to svět plný pravděpodobností a kalkulovaných rizik, kde se spoléháme, že ani nejvýkonnější počítat za x let nebude schopen prolomit bezpečnostní vrstvu naší aplikace.
Schválně si ověřte, jak dlouho by trvalo prolomit obdobné heslo tomu vašemu, správce hesel Bitwarden nebo NordPass vám udělají odhad. Je třeba ho samozřejmě brát s rezervou, ale pro hrubou představu to není vůbec špatné.
Problém je, že i když si zvolíte heslo, které potrvá prolomit tak dlouho, že i Slunce tou dobou už bude dávno vyhaslé, nezabráníte možnosti, že si útočník nenajde jinou cestu, jak získat přístup k vašemu účtu. Např. se můžete stát součástí phishing útoku a heslo útočníkovi můžete sdělit omylem vy sami. V domění, že se přihlašujete do vaší staré známé aplikace, vyplníte svoje přihlašovací údaje a nepatrně jiné URL adresy si všimnete, až když už je pozdě.
Ať už by útočník k heslu mohl přijít jakkoliv, je lepší mít navrženou bezpečnostní vrstvu tak, že ani uniklé heslo, neprolomí přístup do vašeho účtu. Jak? Právě díky více-faktorovému ověření uživatele, konkrétně jak zmiňuje OWASP:
MFA je ověření uživatele alespoň dvěma faktory, které můžeme rozdělit do tří hlavních kategorií:
- něco, co víte: heslo, PIN, bezpečnostní otázka, …
- něco, co máte:
- chytrý telefon:
- pro příjem jednorázového (SMS) kódu (OTP – one-time-password)
- pro vygenerování časově-jednorázového kódu pomocí aplikace jako je Google Authenticator (TOTP – time-based one-time-password)
- USB bezpečnostní klíč
- chytrý telefon:
- něco, co jste: biometrické ověření (otisk prstu, rozpoznání obličeje)
V citaci výše OWASP dokonce zmiňuje právě FIDO2 passkeys, jako možnou řešení MFA, která je uživatelsky přívětivější než stávající metody.
Co jsou tedy passkeys?
Zjednodušeně řečeno se jedná o snadnější a bezpečnější způsob, jak ověřit uživatele. Místo hesla je možné použít např. otisk prstu nebo rozpoznání obličeje, záleží na typu autentizátoru, který vaše zařízení podporuje.
Koneckonců zkuste si to sami, zde je plně funkční demo, přes které lze passkey vytvořit a pak se s ním znovu přihlásit do aplikace:
🖼️ Demo: with-webauthn.dev
👨💻 Zdrojový kód: github.com/cermakjiri/with-webauthn
Co jsou FIDO2 passkeys?
FIDO2 (Fast IDentity Online 2) je sdílený projekt mezi FIDO Alliance a W3C (World Wide Web Consoritum) s hlavním cílem vytvořit nový soubor bezpečných standardů pro ověřování identity uživatelů na webu. Místo ověření uživatele pomocí uživatelsky vytvořeného hesla, daný autentizátor:
- Vygeneruje kryptograficky provázaný pár klíčů.
- Privátní klíč podepíše challenge vygenerovanou vaším serverem (tzv. relying party).
- Autentizátor vrátí veřejný klíč a podpis*, tedy public-key credential nebo-li populárně řečeno passkey.
- Privátní klíč není sdílen, zůstává v autentizátoru**.
*Autentizátor, kromě veřejného klíče a podpisu, vrátí mnoho dalších informací, které probereme níže v kapitole: Jak vytvořit nový passkey.
**To platí jen pro tzv. device-bound passkeys. Podrobněji rozebráno později.
Konkrétně, FIDO2 má dvě základní složky:
- Client to Authenticator Protocol 2 (CTAP2) – komunikační protokol mezi kryptografickým autentizátorem (jako je např. FaceID, TouchID, nebo hardwarový bezpečnostní klíč) a klientem (např. user agent).
- W3C Web Authentication (WebAuthn) – API dostupné v prohlížeči, přes které inicializovat vytvoření a použití takového passkey.
WebAuthn API nabízí momentálně “pouze” dvě metody:
navigator.credentials.create(...)
: Vytvoří passkey během tzv. attestation ceremony.navigator.credentials.get(...)
: Získá passkey během tzv. assertion ceremony.
Kombinaci parametrů, které přijímají, je opravdu veliká. W3C WebAuthn specifikaci můžete nalézt zde, přístupněji to pokrývá MDN nebo Google Developers.
Jak vytvořit nový passkey?
Zavoláním navigator.credentials.create(...)
metody vytvoříme nový passkey, procesem zvaným jako attestation ceremony:
Detailnější proces vytvoření passkey:
Klient pošle API request na server s uživatelským jménem.
Server vygeneruje
challenge
společně s dalšími povinnými parametry:pubKeyCredParams
(COSEAlgorithmIdentifier
)- Pole asymetrických algoritmů pro vytvoření podpisu, které váš server (relying party) podporuje. Ne každý autentizátor může podporovat všechny asymetrické algoritmy, proto je dobré ji uvést co nejvíce. Kompletní seznam zde.💡Pokud budete požadovat použití algoritmu, který daný autentizátor neumí, dostanete tento error, který není lehké zpětně odůvodnit:
DOMException: The operation either timed out or was not allowed. See: https://www.w3.org/TR/webauthn-2/#sctn-privacy-considerations-client.
- Pole asymetrických algoritmů pro vytvoření podpisu, které váš server (relying party) podporuje. Ne každý autentizátor může podporovat všechny asymetrické algoritmy, proto je dobré ji uvést co nejvíce. Kompletní seznam zde.
rp
(relying party): Doména v jaké bude možné použít passkey.user
:id
: Base64 URL formátname
: uživatelské jméno, např. emaildisplayName
: jméno uživatele
challenge
: Base64 URL formát
Server zároveň vygeneruje session ID (např. jako serve-side cookie). Pod tímto ID uloží do databáze vygenerovanou challenge a další údaje, které budou potřeba při ověření výsledku autentizátoru.
Klient převede hodnoty z Base64 URL na TypedArray a celou strukturu pošle do
navigator.credentials.create
:
- Klient z
attestationResponse
získá public-key, typy přenosu, použitý algoritmus pro podpis a další informaceAuthenticatorAttestationResponse
. Vše pošle na server k ověření. - Server podle session ID najde v databázi očekávanou challenge a ostatní uložené údaje. Zkontroluje zda session neexpirovala a provede validaci
AuthenticatorAttestationResponse
.
Ze zkušenosti, mohu říct, že parsování AuthenticatorAttestationResponse
není vůbec snadné. Ku příkladu je nutné se popasovat s dekódování CBOR formátu – binární datová reprezentace, kterou si lze představit jako JSON ale pro komunikaci s autentizátory – a následně dodržet všechny podmínky korektní validace. Proto může být vhodnější použít nějakou ověřenou knihovnu, která to udělá za nás, např. SimpleWebAuthn.
V demu používám právě SimpleWebAuthn, jak na klientovi tak serveru. Nicméně alternativ je mnoho, včetně knihoven v jiných jazycích: awesome-webauthn.
Důležité poznatky k vytvoření passkey:
- Passkeys jsou provázané s doménou vaší aplikace (tedy podle
rpId
). Pokud se změní, vytvořené passkeys se stanou neplatnými:- Passkey vytvořený s
rpId: 'example.com'
je možné použít nahttps://example.com
, nikoliv nahttps://subdomain.example.com
. - Passkey vytvořený s
rpId: 'subdomain.example.com'
lze použít nahttps://subdomain.example.com
a také nahttps://example.com
- Tedy platí, že passkeys lze použít na doméně stejného nebo vyššího řádu.
- Pokud potřebuje řešit podporu na různých doménách, existuje experimentální funkce related origins (viz kapitola Jak je to s podporou v prohlížečích).
- Passkey vytvořený s
- Uživatelské jméno nemusí být email, ale může to být vhodná volba. Pokud máte více tzv. authentication providers, pak email může posloužit k jejich propojení. Nebo také z toho důvodu, že v kombinaci s
autocomplete="email"
a funkcí služby typu iCloud+, která vytvoří anonymní email a přeposílá zprávy na uživatelův původní email. Lze tím uživateli pomoc zjednodušit a zabezpečit registrační proces (při úniku dat, unikne pouze alias, nikoliv skutečná emailová adresa). - Pokud chceme zabránit vytvoření více passkeys pro danou službu na jednom autentizátoru pro stejného uživatele (což nejspíš chceme), je třeba vyplnit
excludeCredentials
s existujícími passkeys, které jsme si uložili do databáze. challenge
:- Klíčové pro zabránění replay attacks. Aby byla účinná, musí být generována znovu pro každé použití a obsahovat dostatečné množství entropie: NIST doporučení ohledně minimální délky je 64 bitů (Aktualizováno roku 2020). SimpleWebAuthn generuje challenge s délkou 256 bitů.
- Kvůli bezpečnosti je důležité, aby server vaší relying party dočasně uložil vygenerovanou challenge, dokud není proces registrace dokončen, a použil správnou challenge při ověření (stejně jako při použití passkey, tj. během assertion ceremony). SimpleWebAuthn v dokumentaci navrhuje možné řešení. Obdobné řešení je implementováno i v demu (včetně bezpečnostních doporučení OWASP pro nastavení sever-side cookie).
Typy autentizátorů
Aktuální verze WebAuthn API umí komunikovat s celou řadou kryptografikých autentizátorů, které dělíme na:
- Platform authenticators: Umístěné v zařízení: biometrické senzory, PIN, pattern.
- Roaming (cross-platform) authenticators: Připojitelné pomocí USB, bluetooth, NFC, či jejich kombinací.
WebAuthn API:
Platform authenticator:
Roaming (cross-platform) authenticator:
Bez specifikovaného typy:
Konkrétní UI se může lišit v závislosti na operačním systému a prohlížeči. Zde jsou ukázky z Mac OS, Chromium.
Jak použít stávající passkey?
Zavoláním navigator.credentials.get(...)
metody získáme existující passkeys, procesem zvaným jako assertion ceremony.
Ilustruji zde tři variace použití: První je přihlášení uživatele do aplikace, druhá je ověření uživatele v aplikaci, který je již přihlášen (tj. např. před provedením citlivé akce, kde chceme mít jistotu uživatelské přítomnosti) a třetí ukazuje přihlášení do aplikace pomocí tzv. passkeys autofill.
Přihlášení uživatele do aplikace (minimální flow):
Nevyžaduje žádné username, ani seznam existujících passkeys, stačí
challenge
vygenerovanou vaší relying party a prohlížeč nabídne seznam všech passkeys pro aktuální doménu – takovéto passkeys nazýváme discoverable credentials (dřívější terminologií resident keys):Proces použití passkey:
- Server vygeneruje
challenge
:
- Klient převede
challenge
na TypeArray a zavoláget
methodu:
- Uživateli se zobrazí seznam všech dostupných passkeys pro danou službu:
- Server vygeneruje
Ověření přihlášeného uživatele: Před provedením citlivé akce specifikujeme passkey, pod kterým je uživatel již přihlášen – vyžadujeme znovu-ověření uživatele:
Server kromě
challenge
vrátí i daný passkey (allowCredentials
) – tj. passkeyid
a typy (transports
), jakými lze připojit daný autentizátor:Opět, server vygeneruje session ID (např. jako serve-side cookie). Pod tímto ID uloží do databáze vygenerovanou
challenge
a další údaje, které budou potřeba při ověření výsledku autentizátoru.Jelikož se jedná o citlivou akci, nastavíme
userVerification: 'required'
:A ještě podstatnější je zkontrolovat
assertionResponse
, že autentizátor skutečně provedl user verification. Viz kapitola Co je user presence & user verification?Uživateli se přímo zobrazí ověření pro daný passkey:
Passkey autofill: Nebo-li conditional mediation (conditional UI) je možnost, jak zlepšit UX přihlášení pomocí passkeys. Uživateli jsou, podobně jako v první ukázce použití passkey, nabídnuty všechny dostupné (discoverable) passkeys, v tomto případě ale v rámci select input options:
Server tentokrát nevrací žádné
allowCredentials
:Klient musí specifikovat
mediation
parametr:Zároveň musí u daného HTML prvku nastavit
autocomplete="webauthn ..."
atribut:
Důležité poznatky k použití passkey:
Zavolání
navigator.credentials.get(...)
musí proběhnout, co nejdříve, po načtení stránky – než uživatel klikne do daného inputu.V rámci passkeys autofill se používá také
navigator.credentials.get(...)
. V tomto případě ale vracíPromise
, který se dostane do stavuresolved
, až když uživatel vybere nějaký z nabízených passkeys.Což také známené, že pokud uživatel žádný passkey nevybere a klikne na tlačítko přihlásit, aplikace znovu zavolá
navigator.credentials.get(...)
a dostanete error:OperationError: A request is already pending
. Je proto nutné předchozí požadavek nejprve zrušit pomocíAbortController API
:userHandle
vassertionResponse
odpovídá user ID vygenerované při attestation ceremony (při vytváření passkey) – MDN docs. Může se hodit pro zjednodušení přihlašovacího procesu. User ID je sice nullable, ale musí být vždy definovaný pro discoverable credentials.
Nejzákladnější forma ověření uživatele je tzv. user presence (UP flag) – uživatel pouze stiskne tlačítko na svém autentizátoru, např. na USB bezpečnostním klíči, a tím potvrdí svoji přítomnost.
Oproti tomu user verification (UV flag) vyžaduje ověření uživatele, podle možnosti autentizátoru: tj. PIN, otisk prstu, gesto, apod. Díky tomu server (relying party) může určit, zda se jedná o stejného uživatele, avšak nikoliv určit přesnou identifikaci uživatele.
Daný autentizátor výsledky UP i UV zakóduje, společně s ostatními boolean hodnotami (flags), do Authenticator Data.
Server (relying party) následně tyto flags projde a určí, zda byl uživatel ověřen či nikoliv: kompletní seznam podmínek ověření pro assertion ceremony.
Z pohledu klienta (relying party), tedy parametrů poslané do get
a create
metod, lze pouze vyslovit přání, jak moc má autentizátor vyžadovat ověření uživatele:
userVerification: UserVerificationRequirement
required
: Relying party požaduje UV a značí je pokud se uživatel neprokáže, operace selže.preferred
(výchozí): Relying party preferuje provést UV. Operace ale neselže, pokud to možné není.discourage
: Relying party preferuje přeskočení UV.
Ze zkušenosti, použití hodnoty discourage
na Mac OS, nemá žádný efekt na Touch ID. Po uživateli je vždy požadován otisk prstu.
Hlubší rozbor lze nalézt na web.dev – userVerification deep dive nebo přímo oficiální WebAuthn specifikaci.
Kolika faktorové je ověření pomocí passkeys?
Všechny WebAuthn autentizátory splňují kategorii něco, co máte. Pokud navíc podporují user verification, jedná se o více-faktorové autentizátory. Tedy autentizátory podporující PIN, splňují faktor něco, co víte a biometrické autentizátory zase něco, co jste.
Synchronizace & mazání passkeys
Na začátku jsem v rámci popisu vytvoření passkey napsal, že privátní klíč zůstává bezpečně uložen v autentizátoru. Toto tvrzení se po zkušenosti s passkeys nezdá moc pravdivé. Koneckonců už v rámci dema jste si mohli všimnout, že pokud vytvoříte nový passkey, je vám nabídnuto uložení do iCloud klíčenky a jejich alternativám na jiných OS, resp. prohlížečích:
Oproti tomu pokud jste zvolili uložení např. přímo do prohlížeče:Podle toho, kde je uložen privátní část, dělíme passkeys na:
Synced passkey: public-key credential, jehož privátní klíč může být přenes mimo zařízení původu. Pokud použijete Touch ID, Face ID bude se jednat vždy o passkey. Passkeys existují až od verze WebAuthn 3. Je to sice kompromis mezi bezpečností a použitelností, ovšem právě díky tomu dochází k široké adopci WebAuthn. V demu ho pak uvidíte jako:
Device-bound passkey: public-key credential, jehož privátní klíč zůstává uložen v zařízení původu. Jedná se bezpečnější způsob použití WebAuthn než passkey, ale pokud z principu definice nelze daný public-key credential obnovit. Takovýto public-key credential bude vytvořen, např. pokud zvolíte uložení do prohlížeče nebo máte k dispozici USB security key (např. Trezor nebo Yubikey). V demu ho pak uvidíte jako:
A co na to WebAuthn specifikace?
WebAuthn 3 nově oproti WebAuthn 2 nabízí možnost přenést privátní klíč (resp. celý credential public key source) mimo zařízení původu, ale už nespecifikuje, jak k tomu má dojít.
Pokud jste dříve přišli o daný autentizátor, ztratili se všechny passkeys nadobro. Tomuto šlo předejít pomocí registrování více autentizátorů. Ovšem vytváření právě takových záloh, není moc uživatelsky přívětivé. Tento problém je nyní vyřešen právě díky sync-passkeys, které jsou uložené typicky různých cloudových klíčenkách, podle toho jakou platformu používáte – iCloud klíčenka, Google Password Manager a údajně někdy brzy i Windows Hello.
Je to bezpečné? V rámci Apple ekosystému:
- Privátní klíč je přenesen na cloud přes kanál s koncovým šifrováním.
- K přenosu a uložení je použita AES šifra s délkou klíče 256 bitů (od iOS 12).
- K uložení do iCloud je nutné mít u Apple účtu nastavené 2-faktorové ověření.
Pokud se vám varianta přesunutí passkeys na cloud nezamlouvá, stále existuje možnost si pořídit fyzický bezpečnostní klíč a zachovat si tak plnou kontrolu nad místem úložiště.
Postup je obdobný jako při získání user presence (UP) a user verification (UV) flags, který jsem popisoval výše v rámci assertion ceremony. Zde místo bitu na pozici 0 (odpovídající UP) a bitu na pozici 2 (odpovídající UV), potřebujeme:
Bit na pozici 3 s hodnotou pro Backup Eligibility (BE) flag. Tato hodnota nám říká, zda je možné přenést zdroj passkey (tedy privátní klíč a další data) mimo autentizátor, kde byl daný privátní klíč vygenerován.
- Typ přenosu nemusí být pouze na cloud, ale i manuálním importem/exportem, přes lokální sít nebo např. peer-to-peer synchronizace. Alespoň tak zní specifikace.
- Pokud se jedná přenositelný passkey, nazýváme ho multi-device credential, v opačném případě se jedná o single-device credential.
- Tuto informaci získáme během vytvoření passkey – attestation ceremony.
Bit na pozici 4: Backup State (BS): Byl už zdroj passkey přenesen?
Kompletní parsování dat autentizátoru umí provést již zmíněná SimpleWebAuthn. Klient jen odpověď z autentizátoru pošle na sever, kde zavolá:
Pro nadšence bitové manipulace, CBOR formátu a znalosti jiných low-level pojmů, přikládám funkci této knihovny na parsování authenticator data – parseAuthenticatorData.ts.
Umí nám WebAuthn poskytnout kryptografický důkaz o původu autentizátoru a tedy co je a kdy není attestation? Jak poznat na jakém autentizátoru byl passkey vytvořen? 👇
Authenticator Attestation Globally Unique Identifier (AAGUID) je 128-bitový identifikátor typu (tj. značky, modelu) autentizátoru. Je zvolen výrobcem a měl by být unikátní napříč všemi autentizátory.
WebAuthn attestation je důkaz, že autentizátor opravdu pochází od daného výrobce. Tento důkaz si můžeme kryptograficky ověřit díky tzv. chain of trust a můžeme tedy bezpečně tvrdit, zda podpis pochází z řetězce certifikátů započatým tzv. root certifikátem či nikoliv.
Ve výchozím nastavení create
metoda nepoužije tento způsob ověření. Je proto vhodné upravit attestationType
:
SimpleWebAuthn tohle zvládne udělat za nás (pokud je tedy attestationType: 'direct'
) a podle fmt
(attestation statement format) automaticky vybere odpovídající root certifikát. Pro pokročilejší použití nabízí i SettingsService
třídu se kterou lze nastavit vlastní root certifikát nebo ověřit aktuálně použitý. Výchozí root certifikáty, které používá naleznete zde, což si můžete porovnat s oficiálním root certifikátem např. firmy Apple.
Projekt passkey-authenticator-aaguids seskupuje soubor všech dostupných autentizátorů (název, logo, atd.), což se může hodit při vytváření UI registrovaných passkeys uživatele.
Důležité poznatky:
Některé platformy, které implementovali synced passkeys, nepodporují attestation. Tedy i když nastavíte
attestationType: 'direct'
, vrátí vám autentizátor výsledek, kdefmt
jenull
.Toto aktuálně platí pro Apple:
Také pro Android:
Aktuálně, Windows Hello údajně naopak podporuje pouze bound-device passkeys, tedy i attestation (Window 11). Výhledově ale plánuje implementaci synced passkeys a uživatel by měl tedy možnost si vybrat.
Jak passkey smazat?
WebAuthn API nabízí metody create
a get
, ale co delete
? Momentálně nic takové dostupné není.
Passkey se skládá z veřejné části, uložené v databázi naší aplikace a privátní časti, uložené v cloudu, autentizátoru či jiných místech. Z pohledu naší aplikace lze provést smazání této veřejné části z databáze a omezit nabízené passkeys při přihlášení pomocí allowCredentials
parametru. Dále můžeme uživateli ilustrovat (podle platformy, resp. AAGUID), jak může odstranit privátní část, viz How to Delete a Passkey on Apple, Windows and Android.
Bude to lepší? Na tento nedostatek cílí WebAuthn Signal API z nová verze WebAuthn specifikace.
O co tedy jde? Cílem je, aby relying parties mohli hlásit informace o zrušených nebo prostě jen nesprávných passkeys (např. se při změně uživatelského jména). Tato komunikace má být dostupná skrz nové metody:
Smazání passkey (oficiální návrh API):
Smazání mnoha passkeys oznámením všech přijímaných passkeys (oficiální návrh API):
Změna detailů uživatele (oficiální návrh API):
Je to hudba budoucnosti, uvidíme, jak blízké. Aktuálně si to lze vyzkoušet v Chrome Canary, viz oficiální demo.
Jak je to s podporou v prohlížečích?
Jedná o široce adoptovanou technologii napříč platformami. Je ale dobré podotknout, že Windows Hello aktuálně podporuje pouze bound-device passkeys, synced passkeys prý přijdou brzy.
Stabilní funkce:
Funkce | Chrome | Edge | Firefox | Safari | Zdroj |
---|---|---|---|---|---|
🟢 Základní WebAuthn API | 67 | 18 | 60 | 13 | MDN |
🟢 Autentizátoru podporující ověření uživatele | 67 | 18 | 60 | 13 | MDN |
🟢 Passkeys autofill | 108 | 108 | 119 | 16 | MDN |
Aktuální verze | 131 | 130 | 133 | 18 |
Chystající se funkce:
Funkce | Chrome | Edge | Firefox | Safari |
---|---|---|---|---|
🟡 Related origins | 128 | 128 | Unknown stand. | 18 |
⚪ WebAuthn Signal API | Canary | Unknown stand. | No public comments. | Positive stand. |
- Pro detailnější rozpis, mrkněte na passkeys.dev/device-support.
- Specifika pro jednotlivé platformy najdete na passkeys.dev/docs/reference.
Bezpečnostní rizika & soukromí uživatelů
Odhalení nechráněných účtů
Představme si situaci, máme přihlášení pomocí klasického uživatelského jména a hesla. Zároveň nekteří uživatelé mají jako nastavený přihlášení pomocí passkey. Útočník zkouší různá uživatelská jména, relying party vrátí existující passkeys (tedy jejich IDs a způsob přenosu) v allowCredentials
argumentu nebo vyhodí error, pokud pro daný účet neexistují žádný passkeys. V obou případech, může útočník detekovat, které účty jsou nechráněné pomocí WebAuthn a které tak můžou být slabší na prolomení.
Jak se tomu bránit?
Řešením může být např. vyplňovat allowCredentials
vždy, ať už pravými nebo pseudo-náhodnými hodnotami deterministicky odvozenými z uživatelského jména. Pro uživatel se nic nezmění, autentizátor nabídne pouze validní passkeys. Další variantou je použití výhradně discoverable credentials a tedy nastavit allowCredentials: []
, což zároveň brání i potencionální de-anonymizaci přes passkey IDs.
Zároveň může být lepší nevracet ze serveru specifické chyby napovídající útočníkovi (ano, je to balance mezi UX a bezpečnostní).
Zdroj: w3c.github.io
Detekce existujících účtů
V případě, že je email použit jako uživatelské jméno při registraci uživatele a abychom předešli situaci, kdy útočník může zjistit, zda daný email má uživatel vytvořený účet, může být vhodné, nejprve zaslat na danou emailovou adresu jednorázový kód. Tím ověřit, že ji uživatel skutečně vlastní a teprve pak pokračovat s vytvořením passkey.
Zdroj: w3c.github.io
Více ohledně bezpečnosti a soukromí passkeys můžete najít v oficiální WebAuthn specifikaci.
Stojí za to jít do toho?
I když to nejspíš není z tohoto článku patrné, osobně jsem z této technologie opravdu nadšený. Po dlouhé době vidím webovou technologii, která reálně dokáže zlepšit produkt pro koncové uživatele a při správné implementaci, významně zlepšit bezpečnost i usnadnit autentizaci.
Pokud stále nevěříte, že passkeys dokáží zlepšit váš produkt:
- How KAYAK reduced sign in time by 50% and improved security with passkeys
- How Yahoo! JAPAN increased passkeys adoption to 11% and reduced SMS OTP costs
A jestli už přemýšlíte, jak provede integraci passkeys do svého produktu, mohu doporučit:
- Designing the user experience of passkeys on Google accounts
- Edukační stránka od členů W3C: passkeys.dev
Pro vývojáře:
- Passkeys developer guide for relying parties
- TypeScript WebAuthn knihovna: simplewebauthn.dev
- Online WebAuthn debugger: passkeys-debugger.io, příp. debugger.simplewebauthn.dev
Zároveň, prosím, berte v potaz, že se jedná o velmi dynamicky se rozvíjející technologii. Tudíž i přes snahu vše popsat co nejpřesněji, se některé informace mohou stát brzy zastaralé.
Děkuji vám za pozornost, budu rád za váš názor. Pokud si nechcete nechat ujít moje další příspěvky, nejen o passkeys a WebAuthn, sledujte mě na LinkedIn (no spam – moje aktivita je toho důkazem).