Почему ключи доступа (passkeys) безопасны — на схемах: аутентификация, которая не отправляет секрет

· Обновлено: · · Ключи доступа, WebAuthn, FIDO2, Безопасность, Аутентификация, Защита от фишинга, Информационные системы

Новость «снова утекли пароли крупного сервиса» уже никого не удивляет. Хоть каждый год проводи фишинг-тренировки — число попавшихся никогда не становится нулём. «Не используйте пароль повторно, делайте длинным, периодическую смену… уже не надо» — даже советы метались туда-сюда.

Ключи доступа (passkeys), которые за последние годы быстро разошлись, — способ аутентификации, который Apple, Google и Microsoft совместно продвигают как ответ на эту ситуацию.1 Их часто представляют как «удобно — входишь отпечатком или лицом», но суть не в этом. Настоящая ценность ключа доступа в том, что он переносит основание безопасности с «внимательности человека» на «структуру протокола».

  • Пароли утекают из-за невнимательности пользователей, давайте обучать → человек всегда ошибается
  • Давайте учить распознавать поддельные сайты → можно сделать поддельный сайт, который не распознать
  • С ключом доступа → секрета, который надо отправлять, нет с самого начала, и на поддельном сайте подпись не складывается

Статья на схемах разбирает, почему ключи доступа безопасны, начиная с того, что сломано в паролях. Затем прямо отвечает на очевидные вопросы — «синхронизируемые ключи правда безопасны?» и «есть ли слабости?» — и в конце раскладывает практические узлы внедрения в веб-приложения и среды Windows.

1. Сначала вывод

Причины безопасности ключей доступа сводятся к трём пунктам.

  1. На сервере секрета нет. Сервер хранит только открытый ключ — информацию, утечка которой бесполезна. Даже если базу вынесут целиком, «материала для выдачи себя за другого» атакующему унести нечем.2
  2. Секрет по сети не едет. При входе отправляют только подпись одноразового случайного значения (вызова). Закрытый ключ не покидает аутентификатор устройства, поэтому подслушивание или пересылка где угодно на пути секрета не даёт.2
  3. На поддельном сайте подпись не складывается. Ключ доступа привязан к домену сайта, браузер принудительно сверяет домен. Даже если пользователя обманул поддельный сайт, ключ настоящего сайта в кандидатах просто не появляется, а если подпись как-то переслать — проверка её отвергнет.3

Эти три пункта — не отдельные ухищрения, а следствия одного изменения конструкции: с «делим секрет и отправляем его при каждой аутентификации» на «доказываем подписью, что секрет у нас есть». Смотрим по порядку.

Связь терминов — ключ доступа, WebAuthn, FIDO2, CTAP

В этой области терминов много, да ещё статьи зовут ими разное, поэтому сначала только связи. Ключ доступа — не новый протокол, а «название», повешенное на сочетание уже существующих стандартов.21

Термин Полное имя Что обозначает
WebAuthn Web Authentication API (рекомендация W3C) Стандарт между браузером и сайтом. API, которым через navigator.credentials требуют создать пару ключей и подпись
CTAP Client to Authenticator Protocol (альянс FIDO) Стандарт между браузером и внешним аутентификатором. Общение с ключом безопасности или телефоном по USB, NFC, Bluetooth
FIDO2 Общее имя рамки из этих двух. FIDO2 = WebAuthn + CTAP
Ключ доступа (passkey) Среди удостоверений FIDO2 — то, чем можно войти вместо пароля в одиночку (обнаруживаемое удостоверение)

Таблица 1: ключ доступа — имя поверх основания FIDO2, а не имя стандарта

То есть «поддерживать ключи доступа» на языке реализации значит «реализовать WebAuthn». CTAP — слой, которым браузер и ОС занимаются, когда в деле внешний аутентификатор; стороне веб-приложения его трогать не нужно.

Карта знаний этой статьи

Ключ доступа — удостоверение на открытом ключе поверх стандартов WebAuthn и CTAP (вместе FIDO2): закрытый ключ из аутентификатора не выходит, серверу отдают только открытый ключ, утечка которого бесполезна. Ключ создаётся привязанным к домену сайта (RP ID), поэтому на поддельном сайте подпись с самого начала не складывается и фишинг структурно предотвращается. Синхронизируемый ключ доступа взамен зависимости от облачного аккаунта получает устойчивость к потере, устройственно-привязанный запирает ключ в аппаратуре. После внедрения ключей доступа центр практики — сужение сосуществующих запасных средств и усиление потока восстановления аккаунта.

Карта знаний, почему ключи доступа безопасныРисунок, показывающий, что ключ доступа стоит на WebAuthn, FIDO2, CTAP и криптографии с открытым ключом; что привязка к домену через RP ID структурно предотвращает фишинг; разницу синхронизируемого и устройственно-привязанного и их единые точки отказа; место как устойчивая к фишингу MFA; связи остаточных рисков (запасной путь, восстановление аккаунта, кража сеанса)используетиспользуетиспользуетиспользуетиспользуетиспользуетиспользуетиспользуетиспользуетиспользуетиспользуеттребуетиспользуеттребуетпредотвращаетпредотвращаетпредотвращаетснижаетможет вызватьможет вызватьможет вызватьможет вызватьможет вызватьне рекомендуетсярекомендуется дляиспользуетнастраиваетсяхранится внесовместимо срекомендуется дляможет вызватьрекомендуется дляможет вызватьрекомендуется дляможет вызватьрекомендуется дляможет вызватьне рекомендуетсяключ доступаWebAuthnFIDO2криптография с открытым ключомCTAPаутентификаторTPMWindows Helloключ безопасностиустройственно-привязанный ключ доступатребование безопасного контекста (HTTPS)вызов (одноразовое случайное число)RP ID (идентификатор Relying Party)фишингфишинг типа AiTM (через посредника)утечка базы удостоверенийпарольная аутентификацияповторное использование пароля (атака по списку)захват аккаунтакража сеансового cookieодноразовый пароль (TOTP)устойчивая к фишингу MFAMicrosoft Entra IDсинхронизируемый ключ доступахранилище учётных данных платформыNIST AAL3 (уровень гарантии аутентификатора 3)усиление защиты аккаунта платформызлоупотребление потоком восстановления аккаунтаусиление проверки личности в потоке восстановлениясосуществующее запасное средство аутентификацииплановое сужение запасных средств

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 38, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

2. Что сломано в парольной аутентификации

Короткий путь понять безопасность ключа доступа — увидеть слабости пароля как места. В парольной схеме сам секрет при каждой аутентификации путешествует по всему пути.

СерверБраузерПользовательСерверБраузерПользовательСекрет (пароль) в голове【слабость ①】можно угадать / используют повторно【слабость ②】на поддельный сайт вводят так же(на вид не отличить)【слабость ③】секрет течёт по каналуTLS защищает, но на конце снова открытый текст【слабость ④】секреты (хеши) всех пользователей в одном местепри утечке — цель офлайн-перебораВвод пароляОтправка самого пароляСверка с сохранённым хешем

Рис. 1: В парольной аутентификации сам секрет существует на всём пути.

С точки зрения атакующего это конструкция с большим числом удобных мишеней.

  • Слабость ① (пользователь): сила лишь «чтобы запомнить», плюс повтор на нескольких сайтах. Утечка в одном месте растекается на все аккаунты (атака по списку паролей).
  • Слабость ② (момент ввода): достаточно поддельного сайта, неотличимого от настоящего, — пользователь сам отдаст секрет (фишинг).
  • Слабость ③ (канал): TLS мешает подслушать сам канал, но если вставить «узел с видом настоящего» — толку нет (AiTM ниже).
  • Слабость ④ (сервер): даже хеш при утечке базы идёт в офлайн-перебор. Слабые пароли ломаются первыми.

«Тогда добавим одноразовый код (SMS или TOTP)» — классическая многофакторность, но структура «отправляем общий секрет» не меняется. TOTP — общий seed (секрет) у сервера и приложения-аутентификатора, а сгенерированный 6-значный код пользователь всё равно может ввести на поддельном сайте. На практике фишинг типа AiTM (Adversary-in-the-Middle) — поддельный сайт в реальном времени пересылает всё настоящему серверу — пробивает связку пароль + одноразовый код как есть. CISA (киберагентство США) в «устойчивой к фишингу MFA» называет только два способа: FIDO/WebAuthn и PKI вроде смарт-карты (PIV/CAC); FIDO при этом — золотой стандарт. Именно поэтому.4

То есть проблема не в «силе» пароля, а в самой структуре «делим секрет и при каждой аутентификации его отправляем».

3. Суть ключа доступа — не отправлять секрет, а доказать, что он есть

Ключ доступа — удостоверение на открытом ключе поверх двух стандартов: WebAuthn W3C и CTAP альянса FIDO (вместе FIDO2).21 Звучит сложно, конструкция простая.

СерверУстройство пользователялокальная сверкаматематическая пара(сторона, которая делает подпись)Открытый ключутечка бесполезнаинформация «только для проверки»Аутентификатор (сейф)Windows Hello / Face ID /блокировка экрана Android / ключ безопасностиЗакрытый ключотсюда не выходит вообщеОтпечаток / лицо / PIN= только открыть дверь сейфатоже наружу не выходит

Рис. 2: Сущность ключа доступа — пара ключей на каждый сайт. Закрытая сторона с устройства не выходит, у сервера только открытый ключ для проверки.

  • Закрытый ключ — сторона, которая умеет делать подпись; хранится в аутентификаторе устройства (Windows Hello, Face ID/Touch ID iPhone, блокировка экрана Android, ключ безопасности вроде YubiKey) и наружу не выходит.
  • Открытый ключ — сторона, которая умеет только проверить подпись; его и отдают серверу. Обратно вычислить закрытый из открытого вычислительно невозможно, поэтому утечка не страшна.
  • Биометрия (отпечаток, лицо) нужна только чтобы локально открыть дверь сейфа и с устройства тоже не выходит. На сервер биометрия не уходит.1

Регистрация: отдают «только» открытый ключ

Поток, когда на сайте регистрируют ключ доступа.

АутентификаторБраузерСервер (example.com)АутентификаторБраузерСервер (example.com)Сервер получил только«информацию, утечка которой бесполезна»Запрос регистрации (случайный вызов + сведения о сайте)Сделай ключ для этого сайта (example.com)Проверка личности отпечатком / лицом / PIN (локально)Генерация новой пары ключейзакрытый ключ хранится внутриОткрытый ключ + credential ID (ярлык ключа)Отправка открытого ключа + credential IDСохранение как открытый ключ этого аккаунта

Рис. 3: При регистрации по сети идёт и на сервере хранится только открытый ключ.

Важно: пара ключей при этом создаётся привязанной к домену сайта (RP ID). Ключ для example.com работает только на сайте example.com (RP ID — на уровне домена, поэтому со страниц поддоменов вроде login.example.com он доступен, с чужого домена — нет). Эта привязка — основание устойчивости к фишингу ниже.3

И пара ключей каждый раз новая для каждого сайта. Ключи сайта A и сайта B математически не связаны, понятия «повторного использования» нет, материала сопоставить пользователей между сайтами тоже нет.

Аутентификация: возвращают одноразовую подпись

Поток входа. Сравните с парольной схемой (рис. 1).

АутентификаторБраузерСервер (example.com)АутентификаторБраузерСервер (example.com)По каналу течёт только одноразовая подписьукрасть — на следующий вызов не сгодитсяЗапрос входа (одноразовый случайный вызов)Запрос подписи для example.comПроверка личности отпечатком / лицом / PIN (локально)Подпись закрытым ключомвключает вызов + origin + хеш RP IDПодпись (это не сам закрытый ключ)Отправка подписиПроверка подписи сохранённым открытым ключомплюс вызов, origin и RP ID

Рис. 4: При аутентификации секрет тоже не перемещается. Течёт только «одноразовый документ доказательства».

Сервер каждый раз выдаёт новое случайное число (вызов), аутентификатор подписывает «этот вызов + origin, который сейчас видит браузер + хеш RP ID». Сервер проверяет подпись сохранённым открытым ключом и что вызов — тот, что он сам задал, а origin и RP ID — его сайта.5

Следствие этой конструкции — уже выполнены два из трёх пунктов в начале.

  • На сервере секрета нет: хранится только открытый ключ. При утечке атакующий подпись сделать не может — «унести и взломать», как хеш пароля, не получается.
  • Секрет не течёт: украсть подпись с канала недостаточно — вызов одноразовый, повтор (replay) не работает.

Остаётся третье, «на поддельном сайте подпись не складывается» — главный козырь ключа доступа. Отдельный раздел.

4. Почему фишинг «структурно» не складывается

Фишинг против пароля срабатывает, потому что настоящий секрет можно ввести на поддельном сайте. Человек example.com и examp1e.com (особенно уставший) не отличит, а поле пароля работает одинаково на обоих.

У ключа доступа эту сверку делает не человек, а браузер механически. По спецификации WebAuthn браузер может вызвать аутентификатор только когда домен origin, который сейчас показан, соответствует RP ID ключа.3 Что происходит в момент захода на поддельный сайт — на схеме.

Настоящий сервер (example.com)Поддельный сайт (examp1e.com)AiTM-прокси, который пересылает настоящемуБраузерПользовательНастоящий сервер (example.com)Поддельный сайт (examp1e.com)AiTM-прокси, который пересылает настоящемуБраузерПользовательДаже если подпись как-то сделать,в неё включается examp1e.com,и проверка настоящего сервера её отвергнетЗаход на неотличимый экран входа(за кадром) запуск настоящего входаВызовПересылка вызова и запрос подписиСейчас origin — examp1e.comключ для example.com в кандидаты не поставитьПодпись не создаётся (обмануться нечем)

Рис. 5: AiTM-фишинг пробивает пароль + одноразовый код, но с ключом доступа на этапе подписи схема не складывается.

Защита двойная.

  1. Не появляется в кандидатах: браузер перечисляет только ключи с RP ID, соответствующим origin. На поддельном домене ключ настоящего сайта в выборе не появляется — «случайно воспользоваться» нельзя.
  2. Подпись не проходит: в подписываемое входят origin, который подтвердил браузер, и хеш RP ID. Настоящий сервер сверяет это при проверке, подпись с другого origin всегда отвергается.5

Защита пароля от фишинга держалась на усилии «пользователь внимательно смотрит URL». У ключа доступа пользователю вообще не нужно распознать поддельный сайт. Это точный смысл «устойчивости к фишингу (phishing-resistant)» и причина, по которой CISA и NIST (Национальный институт стандартов США) особо выделяют FIDO/WebAuthn.46

Сводка по видам атак.

Атака Пароль Пароль+TOTP Ключ доступа
Угадывание / перебор ✗ слаб △ код мешает, исходный пароль по-прежнему слаб ○ объекта угадывания нет
Повтор (атака по списку) ✗ утечка в одном месте растекается △ ломается с сайтов без кода ○ независимый ключ на каждый сайт
Утечка БД сервера ✗ офлайн-перебор хешей ✗ утекает и seed TOTP (общий секрет) ○ только открытый ключ
Классический фишинг (ввод на поддельном сайте) ✗ ввести можно ✗ код тоже можно ввести ○ не в кандидатах, подпись не проходит
AiTM (пересылка в реальном времени) ✗ пересылается как есть ✗ пересылается вместе с кодом ○ сверка origin, подпись не складывается
Replay (повтор перехваченного) ✗ тот же пароль снова действителен △ код, перехваченный до использования владельцем, действителен (повтор уже использованного правильная реализация отвергает) ○ вызов каждый раз одноразовый

Таблица 2: Сравнение устойчивости по видам атак. Все «○» ключа доступа идут от структуры, а не от эксплуатации и внимательности.

5. Безопасны ли «синхронизируемые ключи доступа»

После предыдущего естественно возникает вопрос. «Вы сказали, закрытый ключ с устройства не выходит — почему тогда ключ, созданный на iPhone, работает на iPad?» — хороший вопрос, ответ: «ключей доступа два вида».

Сначала сводная таблица. Этот и следующий разделы объясняют, почему каждая строка такая.

Аспект Синхронизируемый ключ доступа Устройственно-привязанный ключ доступа
Типичные примеры Связка ключей iCloud, Google Password Manager, менеджеры паролей вроде 1Password Ключ безопасности (YubiKey и т. п.), Windows Hello, ключ доступа в Microsoft Authenticator
Где хранится закрытый ключ Хранилище учётных данных платформы. Между устройствами одного аккаунта копируется в виде со сквозным шифрованием Внутри аппаратуры аутентификатора. За пределы TPM или secure element не выходит
Потеря / смена устройства Вход в тот же Apple ID / аккаунт Google — восстановление на новом устройстве Ключ этого аутентификатора пропадает. Предпосылка — несколько аутентификаторов заранее
Единая точка отказа Облачный аккаунт платформы Само физическое устройство
Для корпоративного управления Ключ лежит в личном облачном аккаунте, организации трудно видеть место и отзывать оптом. Годится для BYOD и малого масштаба Администратор может выдавать и отзывать, место ключа ясно. Для жёстких регламентов
Соответствие AAL NIST При выполнении требований — AAL2. Закрытый ключ можно экспортировать, для AAL3 не годится6 Аутентификатор с аппаратной защитой, из которого ключ не извлечь, может закрывать и требования AAL36

Таблица 3: Сводка синхронизируемого и устройственно-привязанного. Выбор — что важнее: устойчивость к потере или управляемость места ключа.

Устройственно-привязанный ключ доступаКлюч безопасности (YubiKey и т. п.) /Windows Hello /Microsoft Authenticator (Entra ID)Закрытый ключ физически не выходитиз этой аппаратуры (защита TPM и т. п.)Плюс: место ключа одно и ясноВнимание: против потери нужна регистрация несколькихСинхронизируемый ключ доступа (по умолчанию для потребителей)Связка ключей iCloud /Google Password Manager /менеджеры паролей вроде 1PasswordМежду устройствами одного аккаунтасинхронизация со сквозным шифрованиемоператор содержимое не читаетПлюс: сильны к смене / потере устройстваВнимание: нужна защита самого облачного аккаунта

Рис. 6: Синхронизируемый и устройственно-привязанный. «Закрытый ключ на сервер не отправляют» у обоих одинаково, центр защиты разный.

Синхронизируемый ключ доступа — связка ключей iCloud или Google Password Manager синхронизирует закрытый ключ между устройствами одного аккаунта. Важно: синхронизация со сквозным шифрованием. И Apple, и Google прямо говорят: ключ доступа шифруется на устройстве, затем синхронизируется, сам оператор содержимое не читает.78 То есть принцип «закрытый ключ с устройства не выходит» точно смягчается до «закрытый ключ в открытом виде с устройства не выходит», взамен получая устойчивость к смене устройства и потере.

Как это смягчение меняет модель угроз, стоит сказать прямо. Место, которое нужно защищать, сжимается с «серверов каждого сайта» до «одного облачного аккаунта». К утечкам БД сайтов и фишингу устойчивость прежняя, зато захват самого Apple ID / аккаунта Google становится единой точкой отказа. Поэтому на аккаунт платформы, куда кладут ключи, нужна сильнейшая защита (жёсткая блокировка экрана, наведение порядка в средствах восстановления, по возможности физический ключ безопасности). NIST в апреле 2024 выпустил дополнение к NIST SP 800-63B (Supplement 1: Incorporating Syncable Authenticators Into NIST SP 800-63B) и официально зафиксировал: такой синхронизируемый ключ (syncable authenticator) при выполнении требований может закрывать государственный AAL2 (Authenticator Assurance Level 2). Но пока закрытый ключ можно экспортировать, синхронизируемый вариант для AAL3, который требует аппаратно изолированной среды, не используют.6

Устройственно-привязанный ключ доступа — тип, в котором закрытый ключ из аппаратуры не выходит. Типичный пример — ключ безопасности вроде YubiKey; в корпоративном сегменте ключ доступа Microsoft Entra ID (создаваемый в Microsoft Authenticator) тоже устройственно-привязанный.9 Windows Hello при наличии TPM защищает закрытый ключ под TPM. Сам механизм «аппаратный сейф, который ключ наружу не выпускает» — то же основание, что подробно разобрано в статье о TPM.

Ещё: «вхожу ключом с телефона в браузер на ПК» и внезапно просят считать QR — это не просто переход экрана, а гибридный способ подтвердить физическую близость телефона и ПК по Bluetooth (cross-device аутентификация FIDO). Атаку, в которой удалённый злоумышленник через QR просит чужого человека одобрить вход на свой ПК, близость гасит.1

6. Не серебряная пуля — слабость не «исчезает», а «переезжает»

До сих пор речь о силе ключа доступа; честно говоря, ключ доступа не уничтожает атаки, а выталкивает атакующего в более слабые места. Когда вход в дверь укреплён, куда атакующий обходит — на схеме.

АтакующийСама аутентификацияподпись вызова【крепко】Поток восстановления аккаунтазаявить «ключ доступа потерян»,через SMS или почту сбросить настройкии зарегистрировать ключ атакующегоСосуществующий запасной путьесли остались пароль и SMS-вход,самое слабое звено — тамОблачный аккаунтдля синхронизируемых — Apple ID /аккаунт Google как единая точка отказаСеансукрасть cookie после входа —способ аутентификации уже ни при чём

Рис. 7: Когда вход (аутентификация) крепнет, атака уходит в поток восстановления, запасные средства, облачный аккаунт и сеанс.

Четыре остаточных риска, которые нужно держать в практике.

  1. Сосуществующий запасной путь становится самым слабым звеном. Если «ещё и» ключ доступа включили, а пароль и SMS-вход остались, атакующий просто идёт туда. Устойчивость к фишингу на уровне аккаунта ограничена самым слабым способом входа. Ядро внедрения — не добавление ключа, а плановое сужение и отмена запасных средств.
  2. Поток восстановления становится новой поверхностью атаки. Приём: солгать «устройство потеряно», вывести на сброс через поддержку или почту и зарегистрировать свой ключ. Социальная инженерия службы поддержки в обход крепкой аутентификации — уже привычный ход крупных взломов. Чем крепче вход, тем острее вопрос, как устроена проверка личности в восстановлении.
  3. У синхронизируемых ключей облачный аккаунт — единая точка отказа. Как в предыдущем разделе. Нужны защита аккаунта, куда кладут ключи, и для организации — политика, «на какую платформу синхронизацию разрешать».
  4. Кражу сеанса ключ не останавливает. Ключ доступа защищает только момент входа; если сеансовый cookie после входа украдут malware или XSS, способ аутентификации уже ни при чём. Срок жизни токена, привязка, здоровье устройства — отдельный слой работы остаётся.

Это не «ключи доступа лучше не трогать». Замок на входной двери обновили — засовы на окнах всё равно отдельная работа. Наоборот: место слабости становится явным, и ресурсы защиты можно сосредоточить на потоке восстановления и управлении сеансом.

7. Внедрение на практике — WebAuthn API и среда Windows

В конце — узлы со стороны того, кто внедряет.

Повесить вход по ключу доступа на свой веб-сервис

На стороне браузера — только две функции WebAuthn API. Регистрация — navigator.credentials.create(), аутентификация — navigator.credentials.get().

// Регистрация (сторона браузера)
const credential = await navigator.credentials.create({
  publicKey: {
    challenge: challengeFromServer,   // Одноразовое случайное число, которое генерирует сервер
    rp: { id: "example.com", name: "Example" },
    user: { id: userIdBytes, name: "taro@example.com", displayName: "Taro" },
    pubKeyCredParams: [{ type: "public-key", alg: -7 }],  // ES256
    authenticatorSelection: {
      residentKey: "required",        // Сделать обнаруживаемым удостоверением (= ключом доступа)
      userVerification: "required",   // Сделать обязательной проверку личности биометрией или PIN
    },
  },
});
// Открытый ключ берётся из credential.response, а credential ID —
// из credential.id / credential.rawId на верхнем уровне. Ответ
// регистрации тоже нужно проверить на сервере (challenge,
// origin, RP ID) перед сохранением, как при аутентификации

Смысл основных параметров.

Параметр Роль На что смотреть при реализации
challenge Одноразовое случайное число, которое сервер генерирует каждый раз Криптографически непредсказуемое. На сервере проверить «это неиспользованное, которое я сам выдал» и потребить
rp.id Домен, к которому привязывается удостоверение (RP ID) Если опустить — эффективный домен origin вызова. Задать можно только в диапазоне регистрируемых доменов, например example.com с login.example.com
user.id Внутренний идентификатор пользователя на сервере (user handle) Непрозрачное значение до 64 байт. Не класть как есть почту или имя пользователя — сведения, по которым опознать человека2
user.name / user.displayName Строки для UI аутентификатора и браузера, чтобы пользователь выбрал аккаунт Только для отображения. Сервер не должен по ним опознавать аккаунт
pubKeyCredParams Принимаемые алгоритмы открытого ключа в порядке предпочтения Кроме -7 (ES256) стоит указать и -257 (RS256) — шире круг аутентификаторов
authenticatorSelection Требуемые свойства аутентификатора residentKey: "required" делает ключ доступа (обнаруживаемое удостоверение), userVerification: "required" — обязательную проверку личности биометрией или PIN

Таблица 4: Основные параметры navigator.credentials.create()

Замечание для среды проверки: WebAuthn API открыт только в безопасном контексте, поэтому вызов navigator.credentials на странице с голым http:// падает. Исключение — http://localhost127.0.0.1): они считаются доверенным origin, на машине разработки можно пробовать без HTTPS. Но RP ID должен быть эффективным доменом origin (или его родителем), поэтому ключ, созданный на localhost, на боевом домене не работает. Даже без живого аутентификатора вкладка «WebAuthn» в инструментах разработчика Chrome с виртуальным аутентификатором даёт пройти регистрацию и вход целиком.

// Аутентификация (сторона браузера)
const assertion = await navigator.credentials.get({
  publicKey: {
    challenge: challengeFromServer,
    rpId: "example.com",
    userVerification: "required",
  },
  // Предложить ключ доступа как подсказку автозаполнения в поле входа.
  // Сначала проверить поддержку через
  // PublicKeyCredential.isConditionalMediationAvailable(), и на браузерах
  // без поддержки перейти к обычному вызову без mediation
  mediation: "conditional",
  // (у целевого <input> нужен autocomplete="username webauthn")
});
// Проверить на сервере подпись assertion.response

Суть — проверка на сервере. Минимум, который нужно делать всегда.5

  • Сверка вызова: это неиспользованный вызов, который я сам выдал? Одноразовый (защита от replay)? Плюс хранить привязанным к сеансу браузера (попытке входа) на момент выдачи и потреблять только ответ из того же сеанса. Если здесь слабо, атакующий может через браузер жертвы подсунуть подпись на свой вызов и заставить жертву войти в аккаунт атакующего (login CSRF).
  • Сверка origin: origin в clientDataJSON — канонический origin своего сайта (ядро защиты от фишинга).
  • Сверка хеша RP ID: rpIdHash в authenticatorData совпадает с SHA-256 RP ID своего сайта.
  • Тип церемонии и флаги: type в clientDataJSON для аутентификации — webauthn.get, для регистрации — webauthn.create. Флаг UP (пользователь присутствует) в authenticatorData установлен. Если требовали проверку пользователя (UV) — флаг UV тоже.
  • Проверка подписи: подпись корректно проверяется открытым ключом, сохранённым при регистрации.
  • Привязка к аккаунту: предъявленный credential ID (и userHandle) ищется в своей базе, сеанс выдаётся владельцу этого удостоверения. Безусловно верить отдельно введённому имени пользователя — дыра войти «правильной подписью, но как другой».
  • Сохранение и сравнение счётчика подписи: signCount из authenticatorData хранить на удостоверение и проверять, что следующее значение больше предыдущего. Меньше или равно предыдущему (включая равенство) — признак клона аутентификатора. У синхронизируемых ключей часто всегда 0, поэтому два нуля как исключение допускают.

Писать эту проверку руками — источник аварий; берите проверенную библиотеку (для .NET — fido2-net-lib, для Node.js — SimpleWebAuthn и т. п.). Детали спецификации (разбор CBOR, согласование алгоритма, управление вызовами) отдайте библиотеке, себе оставьте хранение и отзыв вызовов, UI нескольких ключей и проектирование восстановления — правильное распределение сил.

Среда Windows и внутренние системы

Для аудитории этого сайта — «те, кому поручены бизнес-системы Windows» — достаточно трёх пунктов.

  • Клиент Windows уже умеет. Windows 11 через Windows Hello умеет создавать, использовать и управлять ключами доступа (Параметры > Учётные записи > Ключи доступа); закрытый ключ при наличии TPM защищается аппаратно.10 WebAuthn через браузер (Edge/Chrome) работает и на Windows 10.
  • В среде Entra ID включают «ключ доступа = способ FIDO2». Microsoft Entra ID поддерживает ключи безопасности и ключи доступа в приложении Microsoft Authenticator (устройственно-привязанные); силой аутентификации условного доступа можно потребовать «устойчивую к фишингу MFA» и ограничить доступ к целевым ресурсам ключами и т. п.9 Переход из мира NTLM и политик срока пароля одним прыжком не делается, поэтому параллельно с инвентаризацией основания аутентификации из статьи про NTLM и Kerberos стандарт — сначала обязать устойчивую к фишингу MFA на учётных записях администраторов.
  • На внутреннем веб-приложении польза та же. Но предпосылка — HTTPS. WebAuthn API работает только в безопасном контексте, поэтому даже для интранет-приложения (кроме localhost при разработке) сначала HTTPS и внутреннее доменное имя, годное как RP ID. После этого RP ID работает и на внутреннем домене. В смысле расставания с паролями на стикерах внутренние системы нередко дают эффект быстрее внешних сервисов.

8. Итог

  • Слабость пароля не в силе, а в структуре «делим секрет и при каждой аутентификации отправляем». Секрет живёт у пользователя, в поле ввода, на канале и на сервере — целей много. Даже одноразовый код проигрывает AiTM-фишингу пересылкой.
  • Ключ доступа — пара открытого ключа на каждый сайт: серверу отдают только открытый ключ, утечка которого бесполезна, при входе шлют только подпись одноразового вызова. На сервере секрета нет, по каналу секрет не течёт.
  • В подпись запечены origin и RP ID, которые подтвердил браузер, поэтому на поддельном сайте ключ настоящего в кандидатах не появляется, а пересылка падает на проверке. Пользователю не нужно распознать поддельный сайт — в этом суть «устойчивости к фишингу»; основание защиты переехало с внимательности человека на структуру протокола.
  • Синхронизируемый ключ синхронизируется со сквозным шифрованием и силён к смене устройства и потере. Взамен место защиты сжимается до облачного аккаунта, поэтому защита самого Apple ID / аккаунта Google — предпосылка. Организация может выбрать и устройственно-привязанный (ключ безопасности, ключ Authenticator в Entra ID).
  • Ключ доступа не уничтожает атаки, а выталкивает их в слабые места. Сосуществующий пароль, поток восстановления аккаунта, кража сеанса остаются поверхностью; ядро внедрения — плановое сужение запасных средств и усиление потока восстановления.
  • Реализация — две функции WebAuthn API create / get плюс проверка на сервере. Проверку не писать самим, отдать проверенной библиотеке; силы — на управление вызовами, UI нескольких ключей и проектирование восстановления.

Похожие статьи

Смежные области консультирования

KomuraSoft LLC занимается поддержкой реализации WebAuthn для входа по ключу доступа во внутренние веб-системы, проектированием развёртывания устойчивой к фишингу MFA в среде Entra ID и Custom Software Development, включая встраивание аутентификации в Windows-бизнес-приложения WinForms/WPF.

Справочные ссылки

  1. Альянс FIDO, Passkeys и How FIDO Works. О том, что ключ доступа как удостоверение FIDO заменяет пароль; о том, что биометрия с устройства не отправляется и служит только локальной сверке; о совместном заявлении Apple, Google и Microsoft в мае 2022 о расширении поддержки беспарольного входа по стандарту FIDO; о гибридном способе использования между устройствами (cross-device) с подтверждением близости через QR-код и Bluetooth.  2 3 4 5

  2. W3C, Web Authentication: An API for accessing Public Key Credentials Level 2 (рекомендация W3C). О том, что WebAuthn — API для создания и использования удостоверений на открытом ключе; о том, что закрытый ключ удостоверения держит аутентификатор, а на сервер (Relying Party) регистрируются только открытый ключ и credential ID; о том, что аутентификация идёт подписью (утверждением) вызова, который шлёт сервер; о целях области действия и защиты удостоверения. Также в тексте использованы положения о том, что API открыт только в безопасном контексте; о том, что при пропуске RP ID берётся эффективный домен origin вызова; о том, что user handle (user.id) — непрозрачное значение до 64 байт и не должен содержать сведения, по которым опознать человека, вроде имени пользователя или почты (§14.6.1 User Handle Contents).  2 3 4 5

  3. W3C, Web Authentication Level 2 — §5.1.3 Create / RP ID validation, §13.4.9 Regarding phishing. О том, что удостоверение открытого ключа ограничено RP ID (идентификатор Relying Party = домен); о том, что браузер (клиент) проверяет соответствие регистрируемого домена origin вызова и RP ID и при несоответствии отказывает в создании и использовании удостоверения; о том, что с поддельного origin чужие удостоверения недоступны и WebAuthn устойчив к фишингу, включая атаки через посредника.  2 3

  4. CISA, Implementing Phishing-Resistant MFA (фактологический листок, октябрь 2022). О уязвимости MFA на SMS, голосе, push и OTP к фишингу, атакам AiTM (пересылка) и усталости MFA; о том, что устойчивыми к фишингу названы аутентификация FIDO/WebAuthn и аутентификация на PKI (смарт-карты и т. п.), а FIDO/WebAuthn — золотой стандарт; о том, что организации стоит начинать переход к устойчивой к фишингу MFA с высокорисковых аккаунтов.  2

  5. W3C, Web Authentication Level 2 — §7.2 Verifying an Authentication Assertion. О серверной процедуре проверки: проверка type, challenge (совпадение с самостоятельно выданным) и origin в clientDataJSON; проверка, что rpIdHash в authenticatorData совпадает с SHA-256 ожидаемого RP ID; проверка флагов User Present / User Verified; проверка подписи сохранённым открытым ключом.  2 3

  6. NIST, Incorporating Syncable Authenticators Into NIST SP 800-63B (дополнение апреля 2024, включено в SP 800-63B 4-й редакции). О том, что синхронизируемый аутентификатор (синхронизируемый ключ доступа) может закрывать AAL2, если закрытый ключ хранится и копируется в синхронизирующую ткань с соблюдением требований; о том, что криптоаутентификатор AAL3 требует аппаратно защищённой и изолированной среды, поэтому синхронизируемый аутентификатор с экспортируемым закрытым ключом на AAL3 не используют; о том, что способы вроде WebAuthn с проверкой origin обладают устойчивостью к выдаче себя за проверяющую сторону (устойчивость к фишингу). Исходный PDF: NIST SP 800-63B Supplement 1 2 3 4

  7. Поддержка Apple, About the security of passkeys. О синхронизации ключей доступа через связку ключей iCloud; о сквозном шифровании связки ключей iCloud, которое не читает даже Apple; о защите синхронизации ключами на устройствах пользователя и о восстановлении через escrow с ограничением частоты. 

  8. Google, Security of Passkeys in the Google Password Manager. О том, что закрытый ключ ключа доступа шифруется на устройстве и затем синхронизируется; о сквозном шифровании, из-за которого сам Google к содержимому закрытого ключа доступа не имеет; о том, что восстановление требует защиты на основе блокировки экрана устройства и т. п. 

  9. Microsoft Learn, Enable passkeys (FIDO2) for your organization. О поддержке Entra ID устойчивой к фишингу беспарольной аутентификации ключами безопасности FIDO2 и ключами доступа Microsoft Authenticator (привязанными к устройству); о включении в политике способов аутентификации и требовании через силу аутентификации условного доступа (устойчивая к фишингу MFA).  2

  10. Microsoft Learn, Support for passkeys in Windows. О поддержке Windows 11 создания и использования ключей доступа через Windows Hello; об управлении сохранёнными ключами в Параметры > Учётные записи > Ключи доступа; о аппаратной защите удостоверений Windows Hello, когда доступен TPM; об использовании ключа доступа на мобильном устройстве через QR-код. 

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Политика аудита безопасности Windows и расследование журнала событий на практике — как стать ИТ-службой, которая умеет читать 4625

Практическое руководство, чтобы ответить на просьбу «посмотрите журналы неудачных входов». Разбирает связь базовой и расширенной политики...

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

В чём фундаментальное отличие ключа доступа от пароля?
Пароль — схема, в которой пользователь и сервер делят один и тот же секрет и при каждом входе этот секрет отправляют. Секрет живёт везде — в голове пользователя, в поле ввода, на канале, в базе сервера — поэтому все эти места становятся целью атаки. Ключ доступа использует пару открытого ключа; закрытый ключ на сервер не отправляют. В устройственно-привязанном варианте закрытый ключ вообще не покидает аутентификатор; даже в синхронизируемом он выходит с устройства только в виде с сквозным шифрованием. На сервере хранится только открытый ключ — информация, утечка которой бесполезна злоумышленнику, — а при входе по сети идёт только подпись одноразового вызова. То есть «общий секрет», который и был слабостью пароля, просто не существует. Плюс пара ключей создаётся отдельно для каждого сайта, поэтому само понятие повторного использования не складывается.
Биометрия (отпечаток, лицо) уходит на сервер?
Нет. Данные отпечатка или лица нужны только для локальной сверки внутри устройства — открыть дверь сейфа с закрытым ключом — и по замыслу FIDO биометрия за пределы устройства не передаётся. Сервер получает только подпись с установленным флагом, что проверка личности (user verification) состоялась; ни самого отпечатка, ни даже вектора признаков там нет. Где биометрия недоступна, её заменяет PIN, и этот PIN, как PIN Windows Hello, сверяется только локально на устройстве — решающее отличие от пароля в том, что он по сети не едет.
Почему ключи доступа устойчивы к фишингу?
Потому что по устройству схемы пользователю вообще не нужно распознать поддельный сайт. Ключ доступа создаётся привязанным к домену сайта (RP ID), и браузер предлагает только ключи, соответствующие домену той страницы, которая сейчас открыта. Даже если зайти на поддельный домен, неотличимый от настоящего, ключ настоящего сайта в списке просто не появится — обмануться нечем. Кроме того, в подпись запечены подтверждённый браузером origin и хеш RP ID, поэтому даже если подпись переслать, проверка на настоящем сервере её отвергнет. Структурная невозможность аварии паролей и SMS-кодов — ввести настоящие учётные данные на поддельном сайте — и есть фундаментальное отличие от мер, которые держатся на обучении и внимательности.
Если потерять телефон, в аккаунты больше не попасть?
Если это синхронизируемый ключ доступа — тот, что лежит в связке ключей iCloud или в Google Password Manager, — его можно восстановить на новом устройстве, вошедшем в тот же Apple ID или аккаунт Google. Но восстановление хранилища со сквозным шифрованием требует не только пароля аккаунта, но и дополнительной проверки личности, например ввода блокировки экрана (пароля) прежнего устройства; если потеряны и эти средства восстановления, восстановить может не выйти. Важно не отдавать всё одному телефону. Устройственно-привязанные ключи (ключи безопасности, Windows Hello и т. п.) делят судьбу устройства, поэтому для важных аккаунтов стандарт — зарегистрировать больше одного ключа. Большинство служб позволяют зарегистрировать несколько ключей на один аккаунт. Как аннулировать потерянный ключ, зависит от типа. Для синхронизируемого копии на всех устройствах — одно и то же удостоверение, поэтому сначала удалите потерянное устройство или сделайте удалённую очистку на стороне аккаунта платформы (удаление ключа в настройках аккаунта службы разом аннулирует копии на всех устройствах). Для устройственно-привязанного достаточно удалить ключ этого аутентификатора на стороне службы — аннулируется только потерянный ключ. Для организации важно сразу спроектировать и «дублирование, чтобы пользователь восстановился сам», и «процедуру, по которой администратор отзывает ключ при потере».
У ключей доступа тоже есть слабости?
Есть. Точнее сказать, место слабости сдвигается. Сама аутентификация укрепляется открытым ключом, поэтому атакующие бьют в более слабое окружение. Конкретно: если рядом остаются пароль или SMS, это по-прежнему самое слабое звено; есть приём злоупотребить потоком восстановления аккаунта и зарегистрировать свой ключ; для синхронизируемых ключей захват самого облачного аккаунта становится новой единой точкой отказа. Кроме того, кражу сеансового cookie после входа ключ доступа не останавливает — посторонние угрозы сами не исчезают. Внедрение должно закрывать не только «добавить ключи», но и усиление потока восстановления и плановое сужение запасных средств.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог