spinny:~/writing $ vim passkeys-webauthn-passwordless-authentication.md
1~2Adgangskoder er en af de ting, vi har normaliseret, bare fordi vi har levet med dem i årevis. Brugere glemmer dem, genbruger dem, skriv dem, hvor de ikke burde. Teams skal administrere nulstillinger, politikker, hashes, lækager, phishing og support.3~4passkey gør ikke autentificering perfekt, men de fjerner et stort problem: serveren behøver ikke længere at holde en hemmelighed delt med brugeren.5~6## Hvad sker der virkelig7~8En passkey er en legitimation baseret på WebAuthn. Når brugeren opretter det, genererer enheden et nøglepar:9~10- en privat nøgle, som forbliver på enheden eller i adgangskodehåndteringen;11- en offentlig nøgle, som serveren kan gemme.12~13Når du logger ind spørger serveren ikke "fortæl mig adgangskoden". Send en tilfældig udfordring. Enheden signerer det med den private nøgle. Serveren verificerer signaturen med den offentlige nøgle.14~15Det er den fine del: Hvis databasen bliver stjålet, er der ingen adgangskoder inde at knække. Og hvis en bruger ender på et falsk domæne, er passkey ikke gyldigt for det pågældende domæne. Det er ikke kun bekvemmelighed, det er konkret beskyttelse mod phishing.16~17## Browseren fungerer som en bro18~19I browseren er de to vigtigste API:20~21- `navigator.credentials.create()` for at oprette en passkey;22- `navigator.credentials.get()` for at bruge det under login.23~24Men den vigtige logik er på serveren. Serveren skal generere udfordringen, gemme den midlertidigt, verificere svaret, kontrollere kilden og Relying Party ID og derefter oprette sessionen.25~26Klientdelen burde være næsten kedelig: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~42Hvis du opdager, at du implementerer WebAuthn-kryptering i hånden, så stop. Brug et robust bibliotek på serversiden. Fejlene her er ikke "søde fejl", de er autentificeringshuller.43~44## Hvad skal gemmes i databasen45~46Der er ingen grund til at redde halvdelen af verden. Normalt nok:47~48- ID for legitimationsoplysningerne;49- offentlig nøgle;50- tilsluttet bruger;51- enhver verifikationstæller eller metadata;52- transporter, hvis det er nyttigt for UX;53- navn valgt af brugeren;54- oprettelsesdato og sidste brug.55~56Et minimalt bord kan se sådan ud: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~70Så ville jeg tilføje revisionslogfiler og meddelelser: Hvis nogen opretter en ny passkey på min konto, vil jeg gerne vide mere om det.71~72## UX betyder mere end demo73~74Demoen af en passkey er altid smuk: du klikker, Face ID, du er med. Det faktiske produkt er mere kompliceret.75~76Nogen skifter deres telefon. Nogen bruger en låst firmacomputer. Nogle mennesker forstår ikke, hvorfor browseren foreslår en passkey. Nogen mister adgangen til deres enhed.77~78Det er derfor, jeg ikke ville starte med "fra i dag ikke flere adgangskoder til alle". Jeg ville starte sådan her:79~801. passkey valgfrit for interne brugere;812. forslag til at oprette en efter et vellykket login;823. kontoside for at omdøbe og fjerne passkey;834. klar tilbagefald;845. gradvis udrulning i hovedlogin.85~86Teksten i grænsefladen skal være enkel. "Brug din enheds låseskærm" er bedre end "godkend med en beboer FIDO2 legitimationsoplysninger."87~88## Fejl jeg ville undgå89~90Generer ikke udfordringer på klienten. Udfordringen oprettes på serveren og skal kun bekræftes én gang.91~92Stol ikke kun på legitimations-id'et. Du skal bekræfte signatur, udfordring, oprindelse og Relying Party ID.93~94Slet ikke fallbacks, før du har et godt genopretningsflow. Passwordless behøver ikke at blive "hvis du mister din telefon, er du ude for altid".95~96Behandl ikke passkey som en ren frontend-knap. At skjule en knap er ikke sikkerhed: den rigtige verifikation er server-side.97~98## Passkey-først eller passkey-venlig?99~100For et nyt produkt kan du tænke passkey-først. For en eksisterende app foretrækker jeg passkey-venlig: tilføj passkey som en anbefalet metode, mål succes og problemer, og reducer derefter roligt adgangskodevægten.101~102Den ideelle migration mærkes ikke. Brugeren opdager, at det er nemmere at logge ind, ikke at virksomheden har ændret sin autentificeringsprotokol.103~104## Konklusion105~106passkey er interessante, fordi de forbedrer sikkerhed og UX på samme tid, hvilket er sjældent. De er ikke en tryllestav: recovery, kompatibilitet, support og udrulning mangler at blive designet godt.107~108Men den grundlæggende forandring er stærk. Stop med at bede brugere om at opfinde og beskytte hemmeligheder. Du lader enheden underskrive et kryptografisk bevis knyttet til dit domæne. Mindre menneskelig hukommelse, mindre phishing, færre nulstillinger af adgangskode. Jeg vil sige, at de er værd at tage seriøst.109~110## Kilder111~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