Аутентификация без хранения паролей: passkeys, OAuth 2.0 и внешние провайдеры на практике | AdminWiki

Аутентификация без хранения паролей: passkeys, OAuth 2.0 и внешние провайдеры на практике

15 сентября 2026 15 мин. чтения
Содержание статьи

Пароль в вашей базе данных - это общий секрет: он известен пользователю и хранится у вас в виде хеша, поэтому скомпрометирован может быть с любой стороны. Хеширование (Argon2id с параметрами m=64 МиБ, t=3, p=1 либо bcrypt с cost 12) защищает только от мгновенного чтения дампа. Слабые и переиспользованные пароли вскрываются перебором за часы, часть базы подбирается по словарям.

Verizon DBIR несколько лет подряд относит кражу учётных данных к главным векторам первичного доступа: на неё приходится порядка 20-25% подтверждённых инцидентов. Вывод для администратора простой: пока в базе лежат хеши, поверхность атаки остаётся, и правила сложности её не убирают.

Вторая статья расходов - поддержка. Сброс пароля стоит денег: оценки Forrester и Gartner для служб поддержки колеблются в пределах 30-70 долларов США за одно обращение с учётом времени оператора и простоя пользователя. Сервис на 100 000 активных пользователей при 3% обращений в год получает 3000 тикетов и десятки тысяч долларов расходов, которые не создают ценности.

Убрать пароли можно двумя путями. Passkeys (WebAuthn/FIDO2) удаляют пароль как фактор: сервер хранит публичный ключ, приватный остаётся на устройстве. Внешний провайдер аутентификации (OAuth 2.0 и OpenID Connect) переносит проверку подлинности на чужую инфраструктуру, а у вас остаются идентификатор пользователя и метаданные. Схемы не конфликтуют: passkeys включаются как фактор у вашего собственного Identity Provider.

Дальше: устройство WebAuthn, отличия от 2FA, выбор OAuth-потока, сравнение для B2B и B2C, развёртывание Keycloak, поэтапная миграция на passkeys и ошибки, которые ломают вход в продакшене.

Passkeys и WebAuthn: как работает вход без пароля

WebAuthn (часть спецификации FIDO2) строит вход на асимметричной криптографии. При регистрации аутентификатор генерирует пару ключей: приватный остаётся в защищённом хранилище (Secure Enclave, TPM, защищённый элемент аппаратного ключа), на сервер уходят публичный ключ, credential ID и метаданные. При входе сервер отправляет challenge длиной не менее 16 байт, аутентификатор подписывает его вместе с origin и rpId, сервер проверяет подпись публичным ключом.

Роли в протоколе: relying party (ваш сервис, rpId обычно равен домену), клиент (браузер или ОС) и аутентификатор (платформа либо внешний ключ CTAP2). Приватный ключ не покидает аутентификатор, поэтому фишинг теряет смысл: подпись создаётся для конкретного origin, и поддельный домен получит невалидный ответ. Утечка базы тоже перестаёт быть катастрофой: атакующий видит публичные ключи и ничего не может с ними сделать.

Passkeys - это WebAuthn-учётные данные с синхронизацией между устройствами одной экосистемы: iCloud Keychain с оконечным шифрованием, Google Password Manager, Windows Hello с учётной записью Microsoft. Device-bound вариант (YubiKey, встроенный защищённый элемент) не синхронизируется, зато подходит для привилегированных и админских аккаунтов. Серверная проверка одинакова для обеих разновидностей.

Долю успешных входов определяют UX-детали: conditional UI (WebAuthn autofill), когда браузер предлагает passkey прямо в поле логина, и cross-device сценарий через гибридный транспорт (QR-код на экране, телефон рядом), поддержанный в Chrome 108+, Safari 16 и Android 9+. Resident key (discoverable credential) позволяет входить без ввода логина, а user handle связывает passkey с конкретным аккаунтом.

Технические параметры, которые стоит зафиксировать в требованиях: алгоритмы ES256, RS256 и EdDSA (COSE), режим attestation (none, indirect, direct), флаг user verification для биометрии или PIN, максимальная длина credential ID до 1023 байт. Attestation для B2C обычно не нужен: на BYOD-устройствах он усложняет регистрацию и почти не даёт гарантий.

Чем passkeys отличаются от паролей и 2FA

КритерийПарольПароль + 2FAPasskeys
Что хранит серверХеш пароля с сольюХеш пароля и секрет второго фактораПубличный ключ, credential ID, счётчик подписей
ФишингРаботаетЧастично обходится фишинговыми проксиНе работает: подпись привязана к origin
Последствия утечки базыПеребор, credential stuffingПароли утекают, второй фактор держитсяАтакующий получает только публичные ключи
ВходОдин шаг, но секрет вводится рукамиДва шага, заметное трениеОдин шаг: биометрия, PIN или кнопка на ключе
ВосстановлениеСброс по emailРезервные кодыРезервные коды и второй passkey

Двухфакторная аутентификация снижает риск захвата аккаунта, но пароль остаётся общей тайной и остаётся в базе. Если вы уже прошли путь 2FA, следующий шаг логичен: посмотрите сравнение TOTP, Push, U2F и WebAuthn для корпоративных систем, там разобраны критерии выбора и стоимость владения. Проверьте матрицу совместимости до старта: поддержка passkeys отличается между ОС, браузерами и версиями корпоративных сборок.

Ограничения passkeys, о которых нужно знать до внедрения

  • Потеря устройства: device-bound passkey исчезает вместе с ключом, поэтому нужен второй зарегистрированный аутентификатор или резервные коды.
  • Синхронизация замкнута внутри экосистемы: экспорта passkey из iCloud Keychain в Google Password Manager нет, а корпоративная политика может запрещать облачную синхронизацию.
  • Зависимость от вендора ОС и браузера: изменения в политике платформы вы не контролируете.
  • Legacy-клиенты и CLI: SSH-сессии, скрипты, старые API, VPN-клиенты и мониторинг не умеют WebAuthn, для них остаются ключи, токены и сертификаты.
  • Сервисные и общие учётные записи: passkeys для них не работают, автоматизация требует отдельной схемы доступа.
  • Пользователи без совместимых устройств или с отключённой биометрией остаются без входа, если не предусмотреть fallback.
  • Recovery-механизм обязателен: 8-10 одноразовых кодов, второй passkey и понятная процедура восстановления личности.

Пока passkeys закрывают не все сценарии, вторым фактором остаются TOTP-приложения и аппаратные ключи. Если нужно перевести парк аутентификаторов на открытые решения, пригодится материал о переносе seed-ключей на открытые 2FA-аутентификаторы.

OAuth 2.0 и OpenID Connect: аутентификация через внешнего провайдера

OAuth 2.0 (RFC 6749) решает задачу делегированной авторизации: клиент получает access token и обращается к ресурсам от имени пользователя. OpenID Connect добавляет поверх него аутентификацию: ID Token в формате JWT с утверждениями sub, iss, aud, exp, iat, nonce, azp и эндпоинт UserInfo. Роли распределяются так: resource owner (пользователь), client (приложение), authorization server (внешний IdP), resource server (ваш API).

Потоки (grant types) выбирают по типу клиента: authorization code + PKCE (RFC 7636) для веб-приложений, SPA и мобильных приложений; client credentials для сервис-сервис (M2M) без пользователя; device authorization grant для CLI, телевизоров и устройств без браузера; refresh token для продления сессии. Implicit flow и Resource Owner Password Credentials признаны устаревшими, в новых интеграциях их быть не должно. Актуальные требования собраны в OAuth 2.0 Security Best Current Practice (RFC 9700): обязательный PKCE, точное совпадение redirect_uri, привязка токенов к отправителю (DPoP или mTLS), ротация refresh-токенов.

Для корпоративных клиентов рядом живёт SAML 2.0: многие заказчики требуют именно его, потому что их IdP (Entra ID, Okta, ADFS) настроен на SAML SSO. Если вы строите продукт для B2B, IdP должен уметь и OIDC, и SAML.

Authorization Code + PKCE: базовый сценарий для веб-приложений

  1. Приложение генерирует code_verifier (43-128 символов) и считает code_challenge как BASE64URL(SHA256(code_verifier)), method S256.
  2. Браузер уходит на authorization endpoint IdP с параметрами client_id, redirect_uri, scope=openid profile email, state и nonce, а также code_challenge.
  3. Пользователь аутентифицируется у IdP (пароль, passkey, корпоративный SSO), IdP возвращает code строго на зарегистрированный redirect_uri.
  4. Backend меняет code и code_verifier на токены через token endpoint; для confidential client добавляется client_secret, для публичного клиента PKCE обязателен вместо секрета.
  5. Приложение проверяет подпись ID Token по ключам JWKS, затем iss, aud, exp, iat и nonce.
  6. Токены сохраняются в HttpOnly Secure SameSite cookie по схеме BFF; localStorage для них не подходит.

PKCE защищает от перехвата code в публичных клиентах и от повторного использования перехваченного запроса, state закрывает CSRF, nonce защищает ID Token от replay. Типичная ошибка новичков - расхождение redirect_uri: лишний слэш, http вместо https или нестандартный порт приводят к invalid_redirect_uri и пустому экрану входа.

Что остаётся в вашей базе после перехода на внешний IdP

  • Внешний subject ID (sub) как основной ключ пользователя: email менять можно, sub нет.
  • Email, иногда имя и аватар: это PII, и она подпадает под GDPR и 152-ФЗ.
  • Роли, группы, права и привязка к тенанту или организации.
  • Метаданные сессий и refresh-токены (или ссылки на них), сроки жизни, привязка к устройству.
  • Журнал входов: время, IP, user agent, результат, способ аутентификации.

Пароли и их хеши исчезают полностью, объём чувствительных данных падает на порядок. Дальше работает принцип минимизации: заводите пользователя по технологии just-in-time provisioning при первом входе, беря из токена только нужные утверждения, и не храните то, что можно запросить у IdP. Отдельно проверьте, что удаление пользователя у провайдера корректно закрывает доступ у вас.

Сравнение решений для B2B и B2C: что выбрать

КритерийPasskeys на своей сторонеВнешний IdP в облакеSelf-hosted IdPГибрид
Контроль данныхПолныйУ провайдераПолныйЧастичный
СтоимостьРазработка и поддержка кодаТарифы за MAUСерверы и администрированиеСумма двух статей
Срок до продакшенаНеделиДниДни или неделиНедели
SSO, SAML, SCIMНетОбычно есть в старших тарифахЕстьЕсть
On-prem и закрытый контурДаНетДаДа
Legacy-клиентыЗакрываете выЧастичноЗакрываете выЗакрываете вы

B2B: SSO, SAML и требования корпоративных заказчиков

Корпоративный заказчик приходит с готовым списком требований: вход через его IdP (Entra ID, Okta, Google Workspace), провижининг и депровижининг по SCIM 2.0, аудит доступа с выгрузкой, поддержка SAML 2.0 и OIDC, отсутствие паролей в вашей базе, соответствие ISO 27001 или SOC 2. Passkeys в чистом виде здесь не подходят: сотрудник должен входить тем, что выдал его отдел безопасности, и увольнение должно закрывать доступ автоматически. Рабочая схема: внешний IdP у вас или self-hosted Keycloak, федерация с IdP заказчика, роли собираются из claim groups, а тенант определяется отдельным атрибутом.

Практический пример: мультитенантный Keycloak, где на каждого крупного клиента создаётся отдельный realm, а для остальных используется один realm с несколькими identity providers. Маппинг ролей делайте по стабильному идентификатору группы, а не по её названию: заказчик переименует группу "IT-Admins" в "IT Operations", и вход сломается в самый неподходящий момент.

B2C: UX, поддержка и стоимость владения

В массовом сегменте выигрыш от passkeys виден сразу: вход одним касанием с биометрией, меньше забытых паролей, меньше обращений в поддержку, выше доля успешных входов на мобильных устройствах. Google с мая 2023 предлагает passkeys по умолчанию для личных аккаунтов, платформы Apple и Microsoft поддерживают их нативно, поэтому барьер для пользователя низкий. Ориентиры для планирования: снижение обращений по сбросу пароля в разы и рост конверсии входа на несколько процентных пунктов при корректно включённом conditional UI.

Социальный вход через Google, Apple или Яндекс ускоряет регистрацию и снимает часть поддержки, но добавляет зависимость от правил платформы, ограничивает аудиторию без аккаунтов в этих сервисах и поднимает вопросы приватности. Для B2C нужен fallback: magic link по email, TOTP-приложение или одноразовый код как временный вход. Часть пользователей не готова к passkeys сразу, поэтому резкое отключение пароля обрушит метрики входа.

По стоимости ориентируйтесь так: облачные тарифы считают активных пользователей в месяц и на десятках тысяч MAU превращаются в тысячи долларов ежемесячно; Keycloak и Authentik бесплатны как ПО, но требуют администрирования, мониторинга и обновлений, что на практике означает долю ставки инженера. Self-hosted вариант выгоден при 10 000+ пользователей и наличии закрытого контура.

Пошаговый план миграции на passkeys без потери пользователей

Этап 1: инвентаризация и выбор решения

Составьте список всех точек входа: веб-приложение, мобильные клиенты, админ-панель, VPN, SSH-доступ, CI/CD, внутренние API, панели мониторинга. Для каждой точки зафиксируйте, поддерживает ли она WebAuthn, кто владелец и какой срок жизни у интеграции. Дальше критерии выбора платформы: облако или закрытый контур, поддержка WebAuthn и conditional UI, стоимость на 10 000 MAU, интеграция с вашей текущей базой пользователей, экспорт данных и отсутствие вендор-лока. Кандидаты: Keycloak (self-hosted, Apache 2.0), Authentik (self-hosted), Zitadel, Auth0 и Okta (облако), Entra ID для Microsoft-окружений.

Проверьте версию библиотеки: поддержка passkeys появилась в Keycloak начиная с 24-й версии, а conditional UI требует свежих браузерных SDK. Если сервис собирается на своей стороне, смотрите на зрелость WebAuthn-библиотек для вашего стека и на поддержку resident keys.

Этап 2: пилот и параллельный вход

Включайте passkeys как дополнительный способ входа для пилотной группы из 50-200 человек под feature flag. Conditional UI делайте сразу: без него пользователи не понимают, что можно войти без пароля. Обязательное условие пилота: два passkey на пользователя или резервные коды, выданные до отключения пароля.

Метрики, которые нужно собирать с первого дня: доля успешных регистраций passkey, доля успешных входов, распределение по типам устройств и браузеров, ошибки AUTH_*, время до входа, число тикетов в поддержку. Тестируйте на iOS Safari, Android Chrome, Windows Hello, macOS Touch ID, Firefox на Linux, внешних ключах и cross-device сценарии с QR-кодом.

Этап 3: отключение паролей и обработка исключений

Отключение идёт сегментами: сначала сотрудники и внутренние сервисы, затем новые регистрации без пароля, затем активные B2C-пользователи. Уведомления рассылайте заранее, окно перехода оставляйте 30-60 дней. Исключения, которые придётся поддержать: сервисные аккаунты, legacy-клиенты без WebAuthn, пользователи без совместимых устройств, подрядчики с временным доступом.

План отката готовится до старта: feature flag для возврата пароля на конкретный сегмент, сохранённый резервный фактор, миграционные окна вне деплоев. Целевые показатели завершённой миграции: 60-70% активных пользователей с зарегистрированным passkey, сбросы пароля в поддержке снижены минимум вдвое, доля отказов входа не выросла. Если проверка после релиза показывает проблемы, действуйте по чек-листу диагностики ошибок аутентификации после обновления.

Настройка внешнего провайдера аутентификации: практический пример

Развёртывание Keycloak и базовая настройка realm

Keycloak работает на Java (Quarkus) и ставится в контейнере. Порядок запуска: сначала база PostgreSQL, затем сам Keycloak с явными переменными окружения, чтобы настройки не сбрасывались после перезапуска. Команда запуска выглядит так: docker run -d --name keycloak -p 8080:8080 -p 9000:9000 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=сильный-пароль -e KC_DB=postgres -e KC_DB_URL=jdbc:postgresql://db:5432/keycloak -e KC_DB_USERNAME=keycloak -e KC_DB_PASSWORD=пароль -e KC_HOSTNAME=auth.example.com quay.io/keycloak/keycloak:26.2 start --optimized. В версии 26 переименовали переменные администратора: KEYCLOAK_ADMIN и KEYCLOAK_ADMIN_PASSWORD заменены на KC_BOOTSTRAP_ADMIN_USERNAME и KC_BOOTSTRAP_ADMIN_PASSWORD, старые значения молча игнорируются.

Проверка готовности: curl -sf http://localhost:9000/health/ready, метрики Prometheus доступны на порту 9000 по пути /metrics. Дальше создайте realm, включите политику WebAuthn (RP ID равен домену, user verification по требованиям, attestation none, passkeys включены) и заведите клиента: client_id, client authentication включён для confidential client, стандартный flow, PKCE с методом S256, точный список valid redirect URIs и web origins, front-channel logout. Публичный клиент без PKCE не создавайте.

Для сред с десятками тысяч пользователей хватает инстанса на 2 vCPU и 4 ГБ RAM с managed PostgreSQL, размещённого за reverse proxy с TLS. Если своего железа нет, подойдёт облачная инфраструктура вроде Timeweb Cloud с VDS, базами данных и Kubernetes: инстанс поднимается за минуты, а ресурсы меняются по мере роста нагрузки. Полный порядок развёртывания, кластеризации и бэкапов разобран в отдельном руководстве по установке и настройке Keycloak в Docker и Kubernetes.

Подключение приложения через OIDC и проверка токенов

Приложение начинает с discovery-документа: GET /realms/имя-realm/.well-known/openid-configuration, откуда берутся authorization, token, jwks и end_session эндпоинты. Подпись ID Token проверяется по ключам с /realms/имя-realm/protocol/openid-connect/certs, набор кэшируется по kid, а неизвестный kid означает ротацию ключей и требует перезагрузки JWKS. После подписи проверяются iss (совпадает с issuer), aud (содержит client_id), exp и iat с допуском на расхождение часов 60-120 секунд, azp при нескольких аудиториях.

Роли забираются из realm_access.roles, resource_access.имя-клиента.roles или из claim groups, который настраивается маппером группы. Logout выполняется через end_session_endpoint с id_token_hint: без этого SSO-сессия у провайдера остаётся живой, и следующий вход происходит без запроса пароля. Альтернативы Keycloak с той же логикой: Authentik, Zitadel, облачные Auth0 и Okta.

Типичные ошибки и риски при переходе на аутентификацию без паролей

Ошибки конфигурации OAuth/OIDC

  • redirect_uri mismatch: лишний слэш, http вместо https, другой порт или wildcard, который открывает утечку authorization code на чужой домен.
  • Отсутствие state и nonce: получаете CSRF на callback и replay ID Token.
  • Implicit flow или парольный grant в новом проекте: токены уходят во фрагмент URL или проходят через клиент.
  • client_secret внутри SPA или мобильного приложения: секрет перестаёт быть секретом, его место только на backend.
  • Токены в localStorage: любая XSS уносит сессию. Используйте BFF и HttpOnly cookie.
  • Проверка подписи ID Token пропущена или claims принимаются без валидации iss и aud.
  • Игнорирование ротации JWKS: ключ сменился, и весь кластер получает 401 до перезапуска.
  • Нет допуска на расхождение часов: серверы разошлись на минуту, вход падает с ошибкой валидации exp.
  • Незакрытый logout: SSO-сессия живёт после выхода, особенно на общих рабочих местах.
  • Слабый аудит: невозможно ответить, кто входил и с какого адреса за последние сутки.

Ошибки миграции на passkeys

  • Отключение пароля без recovery и без второго passkey приводит к блокировке аккаунтов и шквалу обращений.
  • Отсутствие conditional UI: пользователи не догадываются о новом способе входа.
  • Игнорирование несовместимых устройств, старых ОС и корпоративных запретов на биометрию.
  • Нет метрик, поэтому регрессию видно только по жалобам в поддержку.
  • Passkeys для сервисных аккаунтов: автоматизация ломается, а ключи уезжают в переменные CI в открытом виде.
  • Неверный rpId и origin: passkeys привязаны к домену, после переезда на новый домен все ключи перестают работать. Настраивайте rpId на родительский домен заранее.
  • Забытый счётчик подписей и логирование ошибок аутентификатора: рассинхронизация выявляется слишком поздно.

Что в итоге остаётся в вашей базе и как это защитить

После миграции в базе остаются внешний subject ID, email и профиль, роли и права, метаданные сессий, ссылки на refresh-токены и журнал входов. Пароли и хеши исчезают, но появляется новая категория чувствительных данных: токены и PII. Refresh-токены храните в виде хешей, привязывайте к устройству, ограничивайте срок жизни и отзывайте при выходе, смене устройства или подозрительной активности.

Минимальный набор мер защиты: шифрование диска и бэкапов, доступ к таблицам пользователей по принципу минимальных привилегий, секреты в Vault или KMS, маскирование email в логах и аналитике, журнал доступа с хранением 90-365 дней. Требования GDPR и 152-ФЗ затрагивают даже такую базу: нужны сроки хранения, понятная процедура удаления по sub и соглашение об обработке данных с провайдером идентификации.

Отдельно оцените риск утечки метаданных: список админов с email и ролями даёт материал для целевого фишинга, даже если паролей в базе нет. Разбор журналов и поиск аномалий входа ускоряет анализ с ИИ: AiTunnel даёт единый API к GPT, Gemini и Claude с оплатой в рублях и без VPN, что удобно для автоматического разбора логов аутентификации.

Чек-лист перед внедрением и что делать дальше

  • Определите цель: убрать пароли как фактор, убрать хранение хешей или и то и другое.
  • Соберите инвентаризацию точек входа и назначьте владельца для каждой.
  • Проверьте совместимость passkeys по матрице устройств, браузеров и корпоративных политик.
  • Настройте recovery: 8-10 одноразовых кодов, второй passkey, резервный фактор для исключений.
  • Протестируйте IdP на стенде: redirect_uri, PKCE, JWKS, logout, clock skew, ротация ключей.
  • Подготовьте дашборд метрик: доля passkeys, ошибки входа, число сбросов, время до входа.
  • Спланируйте откат через feature flag и окна миграции.
  • Настройте аудит доступа и сроки хранения данных.
  • Согласуйте политику PII: что храните, где шифруете, как удаляете.

Начинайте с пилота на внутренней команде: 50-200 человек дадут статистику по устройствам и ошибкам без риска для клиентов. Дальше расширяйте сегменты, держите пароль как fallback и отключайте его только после того, как доля пользователей с passkey перевалит за 60%. Смежные материалы для подготовки: разбор 2FA-приложений и выбор приложения для двухфакторной аутентификации, а также руководство по Keycloak для развёртывания IdP в закрытом контуре.

Поделиться:
Сохранить гайд? В закладки браузера