spinny:~/writing $ less passkeys-webauthn-passwordless-authentication.md
12Паролі — одна з тих речей, які ми нормалізували лише тому, що жили з ними роками. Користувачі їх забувають, використовують повторно, записують там, де не слід. Команди повинні керувати скиданнями, політиками, хешами, витоками, фішингом і підтримкою.34passkey не робить автентифікацію ідеальною, але вони усувають величезну проблему: сервер більше не повинен зберігати таємницю, якою ділиться користувач.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- ID облікових даних;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## Висновок105106passkey цікаві тим, що вони одночасно покращують безпеку та 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