spinny:~/writing $ less passkeys-webauthn-passwordless-authentication.md
12סיסמאות הן אחד מהדברים האלה שנורמלנו רק בגלל שחיינו איתן במשך שנים. משתמשים שוכחים אותם, עושים בהם שימוש חוזר, כותבים אותם היכן שהם לא צריכים. על הצוותים לנהל איפוסים, מדיניות, גיבוב, הדלפות, פישינג ותמיכה.34ה-passkey לא הופכים את האימות למושלם, אבל הם מסירים בעיה ענקית: השרת כבר לא צריך לשמור סוד משותף עם המשתמש.56## מה באמת קורה78passkey הוא אישור המבוסס על WebAuthn. כאשר המשתמש יוצר אותו, המכשיר יוצר זוג מפתחות:910- מפתח פרטי, שנשאר במכשיר או במנהל הסיסמאות;11- מפתח ציבורי, שהשרת יכול לשמור.1213בכניסה לשרת לא שואלים "תגיד לי את הסיסמה". שלח אתגר אקראי. המכשיר חותם עליו עם המפתח הפרטי. השרת מאמת את החתימה באמצעות המפתח הציבורי.1415זה החלק הנחמד: אם מסד הנתונים נגנב, אין בפנים סיסמאות לפצח. ואם משתמש מגיע לדומיין מזויף, ה-passkey אינו תקף עבור אותו דומיין. זו לא רק נוחות, זו הגנה קונקרטית מפני פישינג.1617## הדפדפן פועל כגשר1819בדפדפן שני API העיקריים הם:2021- `navigator.credentials.create()` כדי ליצור passkey;22- `navigator.credentials.get()` כדי להשתמש בו במהלך הכניסה.2324אבל ההיגיון החשוב הוא בשרת. השרת חייב ליצור את האתגר, לשמור אותו באופן זמני, לאמת את התגובה, לבדוק את המקור ואת Relying Party ID, ואז ליצור את ההפעלה.2526חלק הלקוח צריך להיות כמעט משעמם:2728```typescript29const options = await fetch('/api/passkeys/login/options').then((r) => r.json());3031const credential = await navigator.credentials.get({32 publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options),33});3435await fetch('/api/passkeys/login/verify', {36 method: 'POST',37 headers: { 'Content-Type': 'application/json' },38 body: JSON.stringify(credential?.toJSON()),39});40```4142אם אתה מוצא את עצמך מיישם הצפנה WebAuthn ביד, הפסק. השתמש בספרייה חזקה בצד השרת. השגיאות כאן אינן "באגים חמודים", אלא חורי אימות.4344## מה לשמור במסד הנתונים4546אין צורך להציל חצי עולם. בדרך כלל מספיק:4748- מזהה של האישור;49- מפתח ציבורי;50- משתמש מחובר;51- כל מונה אימות או מטא נתונים;52- הובלות, אם שימושי עבור UX;53- שם שנבחר על ידי המשתמש;54- תאריך יצירה ושימוש אחרון.5556טבלה מינימלית עשויה להיראות כך:5758```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```6970אז הייתי מוסיף יומני ביקורת והתראות: אם מישהו יוצר passkey חדש בחשבון שלי, אני רוצה לדעת על זה.7172## UX חשוב יותר מהדגמה7374ההדגמה של passkey תמיד יפה: אתה לוחץ, Face ID, אתה בפנים. המוצר בפועל מסובך יותר.7576מישהו מחליף את הטלפון שלו. מישהו משתמש במחשב חברה נעול. יש אנשים שלא מבינים מדוע הדפדפן מציע passkey. מישהו מאבד גישה למכשיר שלו.7778זו הסיבה שלא הייתי מתחיל ב"מהיום אין יותר סיסמאות לכולם". הייתי מתחיל ככה:79801. passkey אופציונלי עבור משתמשים פנימיים;812. הצעה ליצור אחד לאחר כניסה מוצלחת;823. דף חשבון לשינוי שם ולהסרה של passkey;834. סתירה ברורה;845. השקה הדרגתית בכניסה הראשית.8586הטקסט בממשק צריך להיות פשוט. "השתמש במסך הנעילה של המכשיר שלך" עדיף על "אימות עם אישור תושב FIDO2".8788## טעויות שהייתי נמנע מהם8990אל תייצר אתגרים על הלקוח. האתגר נוצר בשרת ויש לאמת אותו פעם אחת בלבד.9192אל תסמוך רק על מזהה האישור. עליך לאמת חתימה, אתגר, מקור וRelying Party ID.9394אל תמחק תקלות לפני שיש לך זרימת התאוששות טובה. חסר סיסמה לא חייב להפוך ל"אם אתה מאבד את הטלפון שלך אתה בחוץ לנצח".9596אל תתייחס ל-passkey כאל כפתור חזיתי בלבד. הסתרת כפתור אינה אבטחה: האימות האמיתי הוא בצד השרת.9798## Passkey-ראשון או passkey ידידותי?99100עבור מוצר חדש אתה יכול לחשוב passkey-קודם כל. עבור אפליקציה קיימת אני מעדיף passkey ידידותית: הוסף את passkey כשיטה מומלצת, מדוד הצלחה ובעיות, ואז הפחית בשלווה את משקל הסיסמה.101102ההגירה האידיאלית אינה מורגשת. המשתמש מגלה שהכניסה קלה יותר, לא שהחברה שינתה את פרוטוקול האימות שלה.103104## מסקנה105106ה-passkey מעניינים מכיוון שהם משפרים את האבטחה ואת ה-UX בו זמנית, וזה נדיר. הם אינם שרביט קסמים: שחזור, תאימות, תמיכה והפצה נותרו מתוכננים היטב.107108אבל השינוי הבסיסי הוא חזק. הפסיקו לבקש ממשתמשים להמציא סודות ולהגן עליהם. אתה נותן למכשיר לחתום על הוכחה קריפטוגרפית הקשורה לדומיין שלך. פחות זיכרון אנושי, פחות דיוג, פחות איפוסי סיסמה. הייתי אומר ששווה לקחת אותם ברצינות.109110## מקורות111112- [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
:Passkey וWebAuthn: כניסה ללא סיסמה, ללא קסםlines 1-116 (END) — press q to close