Пароли — одна из тех вещей, которые мы стали нормой только потому, что живем с ними уже много лет. Пользователи забывают их, используют повторно, пишут там, где не следует. Команды должны управлять сбросами, политиками, хэшами, утечками, фишингом и поддержкой.
passkey не делают аутентификацию идеальной, но устраняют огромную проблему: серверу больше не нужно хранить секрет, доступный пользователю.
Что происходит на самом деле
passkey — это учетные данные, основанные на WebAuthn. Когда пользователь создает его, устройство генерирует пару ключей:
- закрытый ключ, который остается на устройстве или в менеджере паролей;
- открытый ключ, который может сохранить сервер.
При входе сервер не спрашивает "скажи мне пароль". Отправьте случайный вызов. Устройство подписывает его закрытым ключом. Сервер проверяет подпись с помощью открытого ключа.
И это приятно: если база данных украдена, внутри нее нет паролей, которые можно было бы взломать. А если пользователь окажется в поддельном домене, passkey недействителен для этого домена. Это не просто удобство, это конкретная защита от фишинга.
Браузер действует как мост
В браузере есть два основных API:
navigator.credentials.create(), чтобы создать passkey;navigator.credentials.get(), чтобы использовать его во время входа в систему.
Но важная логика находится на сервере. Сервер должен сгенерировать запрос, временно сохранить его, проверить ответ, проверить источник и Relying Party ID, а затем создать сеанс.
Клиентская часть должна быть почти скучной:
const options = await fetch('/api/passkeys/login/options').then((r) => r.json()); const credential = await navigator.credentials.get({ publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options), }); await fetch('/api/passkeys/login/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credential?.toJSON()), });
Если вы обнаружите, что используете шифрование WebAuthn вручную, остановитесь. Используйте надежную серверную библиотеку. Ошибки здесь — это не «милые баги», а дыры в аутентификации.
Что сохранять в базе данных
Нет нужды спасать полмира. Обычно достаточно:
- идентификатор удостоверения;
- открытый ключ;
- подключенный пользователь;
- любой счетчик проверки или метаданные;
- транспорты, если это полезно для UX;
- имя, выбранное пользователем;
- дата создания и последнее использование.
Минимальная таблица может выглядеть так:
create table passkey_credentials ( id uuid primary key default gen_random_uuid(), user_id uuid not null references users(id), credential_id text not null unique, public_key text not null, name text, created_at timestamptz not null default now(), last_used_at timestamptz );
Затем я бы добавил журналы аудита и уведомления: если кто-то создаст новый passkey в моей учетной записи, я хочу об этом знать.
UX важнее, чем демо
Демо-версия passkey всегда прекрасна: вы нажимаете, Face ID, и вы в игре. Реальный продукт сложнее.
Кто-то меняет телефон. Кто-то использует заблокированный компьютер компании. Некоторые люди не понимают, почему браузер предлагает passkey. Кто-то теряет доступ к своему устройству.
Вот почему я бы не стал начинать с фразы «с сегодняшнего дня больше никаких паролей для всех». Я бы начал так:
- passkey опционально для внутренних пользователей;
- предложение создать его после успешного входа в систему;
- страница учетной записи для переименования и удаления passkey;
- четкий резервный вариант;
- постепенное внедрение в основной логин.
Текст в интерфейсе должен быть простым. «Использовать экран блокировки вашего устройства» лучше, чем «аутентифицироваться с использованием резидентских учетных данных FIDO2».
Ошибки, которых я бы избегал
Не создавайте проблем для клиента. Задание создается на сервере и должно быть проверено только один раз.
Не доверяйте только идентификатору учетных данных. Вам необходимо подтвердить подпись, запрос, происхождение и Relying Party ID.
Не удаляйте резервные варианты, пока не будет выполнен хороший процесс восстановления. Функция «Беспароль» не обязательно означает «если ты потеряешь свой телефон, ты выйдешь навсегда».
Не рассматривайте passkey как кнопку исключительно внешнего интерфейса. Скрытие кнопки не является безопасностью: настоящая проверка происходит на стороне сервера.
Passkey-первый или passkey-дружественный?
О новом продукте вы можете подумать passkey в первую очередь. Для существующего приложения я предпочитаю использовать passkey: добавьте passkey в качестве рекомендуемого метода, измерьте успех и проблемы, а затем спокойно уменьшите вес пароля.
Идеальная миграция не ощущается. Пользователь обнаруживает, что вход в систему стал проще, а не то, что компания изменила протокол аутентификации.
Заключение
passkey интересны тем, что они одновременно улучшают безопасность и UX, что бывает редко. Они не волшебная палочка: восстановление, совместимость, поддержка и развертывание еще предстоит тщательно спроектировать.
Но основные изменения сильны. Перестаньте просить пользователей изобретать и защищать секреты. Вы позволяете устройству подписать криптографическое доказательство, привязанное к вашему домену. Меньше человеческой памяти, меньше фишинга, меньше сбросов паролей. Я бы сказал, что к ним стоит отнестись серьезно.