Passkeys/WebAuthn на backend без паролей

Пароли — это самый слабый узел в системе безопасности любого приложения. Они крадутся через фишинг, подбираются брутфорсом или утекают из баз данных в открытом виде (или в виде слабых хешей). Индустрия пыталась решить это через 2FA/MFA, но это лишь добавило трения для пользователя.
Passkeys (на базе стандарта WebAuthn) предлагают радикальный подход: заменить общий секрет (пароль), который знают и клиент, и сервер, на пару ключей: приватный, который никогда не покидает устройство пользователя, и публичный, который хранится у нас в базе.
Что такое WebAuthn и Passkeys на самом деле?
Если отбросить маркетинговую шелуху, WebAuthn (Web Authentication API) — это стандарт взаимодействия браузера с аутентификатором (TouchID, FaceID, Windows Hello или USB-ключ типа YubiKey).
Passkeys — это эволюция этого стандарта. Главное отличие в том, что теперь приватный ключ может синхронизироваться между устройствами пользователя через облако (iCloud Keychain, Google Password Manager), что решает главную проблему ранних USB-ключей: «что делать, если я потерял флешку?».
С точки зрения бэкенда, мы больше не проверяем соответствие строки password её хешу в БД. Мы проверяем цифровую подпись, пришедшую от клиента, используя сохраненный публичный ключ.
Архитектура процесса: Как это работает «под капотом»
Весь процесс делится на два основных этапа: Регистрация и Аутентификация.
1. Регистрация (Создание Passkey)
Процесс регистрации — это своего рода «рукопожатие», в ходе которого сервер и клиент договариваются о доверии.
- Запрос на создание (Challenge): Сервер генерирует случайную строку (challenge), ID пользователя и параметры алгоритмов, которые он поддерживает. Эти данные отправляются на фронтенд.
- Генерация ключа на клиенте: Браузер вызывает API WebAuthn. Устройство пользователя просит биометрию (отпечаток или лицо). После подтверждения устройство генерирует пару ключей (приватный/публичный) специально для вашего домена.
Отправка ответа: Клиент отправляет серверу:
-
- Публичный ключ.
-
- ID созданного ключа (Credential ID).
-
- Подписанный challenge.
-
- Данные об аутентификаторе (attestation).
Валидация и сохранение: Бэкенд проверяет подпись с помощью полученного публичного ключа. Если всё верно, мы сохраняем Credential ID и Public Key в базе данных, привязав их к аккаунту пользователя.
2. Аутентификация (Вход в систему)
Когда пользователь возвращается, нам не нужно спрашивать пароль.
- Вызов аутентификации: Сервер отправляет новый случайный challenge и список доступных
Credential IDдля этого пользователя (или просит пользователя указать свой email). - Подпись на устройстве: Браузер находит нужный приватный ключ, пользователь подтверждает личность биометрией, и устройство подписывает challenge.
- Проверка на бэкенде: Сервер достает из базы публичный ключ, соответствующий присланному
Credential ID, и проверяет подпись. Если подпись валидна — сессия открыта.
Технические нюансы реализации на Backend
Реализовать WebAuthn «с нуля», вручную парся бинарные данные (CBOR), — это путь к созданию дыр в безопасности. Настоятельно рекомендую использовать проверенные библиотеки (например, fido2-lib для Node.js, python-fido2 для Python или аналоги для Go/Java).
Что важно хранить в базе данных?
Ваша таблица учетных данных должна измениться. Вместо одного поля password_hash, вам понадобится таблица user_credentials со следующими полями:
user_id: Ссылка на пользователя.credential_id: Уникальный идентификатор ключа (обычно Base64 или бинарный вид).public_key: Сам публичный ключ (в формате COSE).sign_count: Счетчик подписей. Это критически важно для защиты от клонирования ключей. Если пришедший счетчик меньше или равен тому, что в базе, значит, ключ был скопирован.transports: Способ передачи (USB, BLE, NFC, Internal), чтобы подсказывать пользователю, как подключиться.
Безопасность и «подводные камни»
При реализации бэкенда обратите внимание на следующие моменты:
-
- Валидация Domain (RP ID): WebAuthn жестко привязан к домену (Relying Party ID). Если вы зарегистрировали ключ на
app.example.com, вы не сможете использовать его наother.example.comбез специальной настройки. Это на корню убивает фишинг: поддельный сайт просто не сможет вызвать приватный ключ для вашего домена.
- Валидация Domain (RP ID): WebAuthn жестко привязан к домену (Relying Party ID). Если вы зарегистрировали ключ на
-
- Challenge Entropy: Challenge должен быть криптографически стойким случайным числом и иметь короткий срок жизни (TTL). Никогда не используйте предсказуемые значения.
-
- Обработка ошибок: Биометрия может сработать не с первого раза, или пользователь может отменить запрос. Бэкенд должен корректно обрабатывать такие сценарии, не разрывая сессию регистрации.
Сравнение: Пароли vs Passkeys (Таблица для бизнеса)
| Критерий | Пароли + 2FA | Passkeys (WebAuthn) |
|---|---|---|
| UX (Пользовательский опыт) | Ввод строки $\rightarrow$ Код из SMS/App | Один клик $\rightarrow$ FaceID/TouchID |
| Безопасность | Уязвимы к фишингу и утечкам БД | Устойчивы к фишингу, в БД нет секретов |
| Стоимость владения | Расходы на SMS-шлюзы, сброс паролей | Бесплатно (используются ресурсы устройства) |
| Сложность внедрения | Низкая (стандарт индустрии) | Средняя/Высокая (нужна новая логика бэкенда) |
Стратегия миграции: Как перейти на беспарольный режим?
Вы не можете просто «выключить» пароли завтра, иначе вы потеряете часть аудитории со старыми устройствами. Рекомендуемый путь внедрения:
- Опциональный второй фактор: Сначала внедрите WebAuthn как альтернативу SMS/OTP для двухфакторной аутентификации.
- Предложение «упростить вход»: После того как пользователь залогинился по паролю, предложите ему: «Хотите входить быстрее? Создайте ключ доступа (Passkey)».
- Постепенный отказ: Когда большая часть активных пользователей создаст Passkeys, сделайте их основным методом входа, оставив пароли как «запасной вариант» (recovery method).
Заключение
Переход на Passkeys — это не просто следование тренду, а решение фундаментальной проблемы безопасности. С точки зрения бэкенда, мы переходим от модели «хранения секретов» к модели «верификации доказательств».
Да, это требует переработки схемы базы данных и внедрения новых API, но профит в виде отсутствия утечек паролей и колоссального улучшения конверсии в логин полностью оправдывает эти затраты. Будущее за беспарольным миром, и сейчас — лучшее время, чтобы интегрировать WebAuthn в ваш стек.

