Две проверки WebAuthn без разрешений, открывающие вход по passkey, выдают класс устройства, версию ОС и движок браузера — слабый, но показательный сигнал.
В августе 2026 года в блоге Android Developers компания Google рассказала, как WhatsApp перевёл на ключи доступа (passkey) 1 миллиард пользователей. Это наглядно показывает, что passkey перестали быть игрушкой для энтузиастов и стали массовым решением по умолчанию. WhatsApp — нативное Android-приложение, но тот же сдвиг происходит и в вебе: прежде чем предложить вход по passkey, страница входа должна спросить у браузера, «умеет ли это устройство работать с passkey?». Эта статья о том, что раскрывает ответ на этот вопрос — и сайту, который его задаёт, и любому другому скрипту, работающему на той же странице.
Главное
- Интерфейс passkey зависит от двух проверок возможностей, и ни одна не требует разрешения.
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()иisConditionalMediationAvailable()возвращают Promise и работают без запроса разрешения, без жеста пользователя и без какого-либо видимого интерфейса — см. спецификацию WebAuthn Level 3 и справочник MDN. - Ответ «да/нет» коррелирует с классом устройства, минимальной версией ОС и движком браузера. Аутентификатор платформы — это встроенная проверка пользователя: Face ID, Touch ID, Windows Hello или блокировка экрана Android. Он привязан к определённым версиям ОС и движкам, поэтому одно логическое значение делит посетителей на группы заметно точнее, чем можно ожидать.
- Энтропии здесь мало, и это надо признать честно. Даже с новым набором
getClientCapabilities()ответы в основном повторяют то, что уже раскрывает User-Agent, поэтому сами по себе почти никого не выделяют. - Настоящая ценность сигнала — в проверке на противоречия, а не в идентификации. Интересен случай, когда User-Agent выдаёт себя за современный флагманский смартфон, а аутентификатора платформы нет: это классический профиль антидетект-браузера или эмулятора.
- Проверка раскрывает только возможности устройства. Она не сообщает скрипту, есть ли у вас passkey для этого или любого другого сайта, и тем более не говорит, кто вы: для этого нужна явная церемония с подтверждением пользователя, ограниченная одной проверяющей стороной.
Две проверки за каждой кнопкой «Войти с passkey»
Чтобы предложить вход по passkey, странице сначала нужно выяснить, способно ли устройство его создать. Для этого в WebAuthn у PublicKeyCredential есть два статических метода; оба определены в спецификации WebAuthn Level 3, которую развивает W3C:
isUserVerifyingPlatformAuthenticatorAvailable()отвечает на один вопрос: есть ли у этого браузера на этом устройстве доступ к встроенному аутентификатору, способному проверить пользователя, — Face ID или Touch ID, Windows Hello (лицо, отпечаток пальца или PIN-код) либо биометрия или блокировка экрана на Android? В MDN он описан как статический метод, возвращающийPromise<boolean>.isConditionalMediationAvailable()отвечает на более узкий смежный вопрос: может ли браузер предложить passkey через автозаполнение прямо в обычном поле имени пользователя, не прерывая страницу модальным окном?
Новые браузеры добавляют третий, более широкий метод — PublicKeyCredential.getClientCapabilities(). За один вызов он возвращает целый набор логических значений: условные get и create, гибридный (межустройственный) транспорт, поддержку аутентификатора платформы для passkey, Related Origin Requests, новые методы «signal» и поддерживаемые расширения. Как и двум старым проверкам, ему нужен только защищённый (HTTPS) контекст.
У этих проверок три общих свойства, важных для нашей темы: они не требуют разрешения, не требуют жеста пользователя и не показывают никакого интерфейса. Страница может вызвать любую из них сразу после загрузки и получить ответ за миллисекунды — посетитель ничего не заметит. Так и задумано: страница входа должна тихо решить, стоит ли вообще показывать кнопку «Войти с passkey». Но именно поэтому ответ может прочитать любой скрипт на странице, а не только код входа, которому он был нужен.
С чем на самом деле коррелирует пара «да/нет»
Одно логическое значение кажется почти ничем — всего один бит. Но это не случайный шум: за ним стоят реальные свойства железа и ПО, и посетителей он делит на группы точнее, чем подсказывает число бит:
- Класс устройства. Аутентификатор платформы обычно опирается на аппаратное хранилище ключей — защищённый анклав (secure enclave), TPM или аппаратное хранилище ключей Android. Старые настольные компьютеры, многие виртуальные машины и некоторые Linux-системы его не предоставляют, а на телефонах ответ зависит ещё и от того, установлена ли блокировка экрана.
- Минимальная версия ОС. Каждая ОС получила поддержку аутентификатора платформы в определённом релизе; ответ
trueозначает, что устройство работает на этой версии или новее, — точнее, чем позволяет большинство других пассивных сигналов. - Движок браузера. Движки поддерживают этот API не одинаково и не одновременно, поэтому ответ заодно сужает круг возможных движков рендеринга и примерно указывает их версию.
- В некоторых конфигурациях — управляемое или виртуализированное устройство. Устройство без аппаратного защищённого хранилища (некоторые ВМ, некоторые жёстко настроенные корпоративные образы) может вернуть
false, даже если заявленные ОС и браузер обычно эту проверку поддерживают.
Сложите всё вместе, и пара логических значений ведёт себя уже не как два бита, а как грубый классификатор по поколению устройства, версии ОС и движку (как устроены такие сигналы, разбирается в нашем руководстве по отпечатку браузера). Но это всего лишь классификатор, а не справочная таблица. Считайте корреляцию реальной и полезной, но не доказательством чего-либо о конкретном устройстве.
Честно об энтропии: несколько бит, а не идентификатор
Переоценить этот сигнал легко — не стоит. Сам по себе isUserVerifyingPlatformAuthenticatorAvailable() даёт один бит, isConditionalMediationAvailable() добавляет максимум ещё один. getClientCapabilities() возвращает больше полей, но они не независимы: большинство из них меняется вместе с брендом и версией браузера, потому что каждый производитель выпускает эти функции пакетами. Хуже того для тех, кто хотел бы использовать это как самостоятельный идентификатор: почти всё это коррелирует с тем, что строка User-Agent и так сообщает об ОС и версии браузера. Добавленный к уже собранному отпечатку, этот сигнал почти ничего не сужает сверх того, что уже сужено.
Его польза в другом — это проверка на противоречия, а не идентификатор. Детектор спрашивает не «какое значение вернулось?», а «согласуется ли оно со всем остальным, что странице уже известно?». Если User-Agent выдаёт себя за актуальный флагманский смартфон, а isUserVerifyingPlatformAuthenticatorAvailable() возвращает false, это несоответствие стоит отметить: настоящие флагманы поставляются с аутентификатором платформы, и почти на всех установлена блокировка экрана. Точно так же не сходится картина, когда User-Agent заявляет свежий Chrome или Safari, а метода getClientCapabilities() нет вовсе. Именно такое несоответствие встречается в профилях антидетект-браузеров и замаскированной автоматизации: одно заявленное свойство (современный User-Agent) не сходится с другим (нет аутентификатора платформы, нет TPM, нет защищённого анклава), потому что профиль собран из частей, а не снят с реального устройства.
На той же идее построен отпечаток медиаустройств и другие проверки оборудования без разрешений: ни одна из них в отдельности вас не опознаёт, но каждая — ещё одно место, где поддельному профилю нужно свести концы с концами, а согласованность подделать труднее, чем любое отдельное значение.
Ирония: создано ради приватности, а само стало небольшим сигналом
Вот о чём стоит задуматься. Ключи доступа создавались, чтобы заменить пароли — секреты, которые можно выманить фишингом и которые люди используют на разных сайтах, — парами ключей, привязанными к одному сайту и не поддающимися сопоставлению между сайтами. И всё же сам API, который даёт это улучшение, раскрывает небольшой пассивный сигнал просто тем, что существует и отвечает true или false.
Две оговорки помогают сохранить трезвый взгляд без паники. Во-первых, для тестирования существуют программные и виртуальные аутентификаторы: инструменты разработчика в браузере и CI-среды могут зарегистрировать виртуальный аутентификатор платформы, который вернёт true на машине вообще без биометрического оборудования, так что проверка не везде гарантирует наличие железа. Во-вторых, проверка не может отличить «аутентификатора нет» от «он не настроен». Телефон с датчиком отпечатка, но без блокировки экрана, или ПК, на котором так и не настроили Windows Hello, для этого API могут выглядеть точно так же, как устройство, где такого оборудования никогда не было. Обе оговорки ведут к одному выводу: это слабый вспомогательный сигнал, а не сильный. Проверка на противоречия ценна тем, что дёшево обходится, а не тем, что решает всё сама.
Чего эта проверка не раскрывает
Здесь важно быть точным, потому что именно преувеличения сильнее всего подрывают доверие читателя:
- Она не раскрывает, есть ли у вас passkey для этого или любого другого сайта. Возможность («умеет ли устройство вообще работать с passkey?») и регистрация («есть ли конкретный ключ для этой проверяющей стороны?») — совершенно разные вопросы, и этот API отвечает только на первый.
- Она не раскрывает вашу личность. Учётные данные WebAuthn по замыслу привязаны к одной проверяющей стороне: passkey, созданный для одного сайта, другой сайт не может прочитать, перечислить или сопоставить, и каждый сайт получает собственную пару ключей, а не общий идентификатор вроде сторонней куки.
- Чтобы использовать настоящий ключ, нужна явная проверка пользователя. Проверка возможностей проходит незаметно, но для реального входа по passkey пользователь всё равно должен пройти биометрию или ввести PIN-код. Сама проверка возможностей ни на шаг к этому не приближает.
Такая привязка — осознанное проектное решение, и она даёт более прочную границу приватности, чем большинство пассивных сигналов отпечатка. Сравните с аттестацией устройства: она делает гораздо более сильное, криптографически подписанное утверждение о конкретном устройстве, а не выдаёт мягкий бит возможностей с низкой энтропией. Проверки поддержки passkey и анонимные учётные данные на этой шкале стоят ближе друг к другу — и те, и другие доказывают узкое свойство, не раскрывая личность, — тогда как аттестация устройства принципиально сильнее и больше идентифицирует. Если вас интересует, как сайты узнают, в какие ваши аккаунты вы вошли, а не что умеет ваше железо, — это совсем другой механизм; см. обнаружение входа на другие сайты.
Что из этого следует
Проверка поддержки passkey — наглядный пример идеи проверки на согласованность, которая проходит через весь этот блог: слабые по отдельности сигналы, сопоставленные друг с другом, ловят больше, чем любой один сильный сигнал. Сама по себе она не отпечаток и не угроза приватности того же рода, что отслеживающая кука или токен аттестации, — но это ещё одно место, где «то, за кого вы себя выдаёте» и «то, что реально умеет ваше устройство» либо сходятся, либо нет.
Наши инструменты пока не проверяют поддержку passkey, но показывают сигналы, с которыми сопоставлялся бы такой ответ: запустите проверку отпечатка, чтобы увидеть User-Agent, платформу и аппаратные характеристики, которые раскрывает ваш браузер, или попробуйте обнаружение ботов, чтобы увидеть, как отмечаются противоречия между этими характеристиками.
Часто задаваемые вопросы
Нужно ли моё разрешение, чтобы проверить поддержку passkey?
Нет. isUserVerifyingPlatformAuthenticatorAvailable(), isConditionalMediationAvailable() и getClientCapabilities() — незаметные проверки на основе Promise: без запроса разрешения, без жеста пользователя, и на странице ничего видимого не происходит.
Может ли сайт узнать, сохранён ли у меня passkey?
Нет. Эти проверки сообщают о возможностях устройства — есть ли вообще аутентификатор платформы, — а не о том, зарегистрирован ли passkey для этого или любого другого сайта. Регистрация учётных данных привязана к конкретной проверяющей стороне и этим API не раскрывается.
Всегда ли результат false что-то значит?
Сам по себе — нет. Он может означать, что у устройства действительно нет аутентификатора платформы, что он есть, но не настроен (например, нет блокировки экрана или Windows Hello не настроен), либо — в тестовой среде — что виртуальный аутентификатор не зарегистрирован. Считайте это одним слабым вспомогательным сигналом, а не окончательным ответом.
Чем это отличается от аттестации устройства?
Сила совсем разная. Проверка возможностей — мягкое логическое значение с низкой энтропией, коррелирующее с классом устройства и версией ОС/браузера. Аттестация устройства — криптографически подписанное, аппаратно подкреплённое утверждение о конкретном устройстве, гораздо более сильное и идентифицирующее.
Рекомендуем почитать:
- Отпечаток браузера: как защитить свою приватность
- Аттестация устройства: Play Integrity против App Attest
- Анонимные учётные данные: доказать, что вы человек, без слежки
- Отпечаток медиаустройств: что раскрывает enumerateDevices
- Обнаружение входа: как сайты узнают, какими сервисами вы пользуетесь
- Невозможные отпечатки: сочетания GPU/ОС/шрифтов, которые вас выдают


