
Театр начинается с гардероба, а сайт начинается со входа.
В статье предложу способ, как без капитального ремонта улучшить ваш «гардероб» и снизить риски кражи вещей из «карманов» пользователей, а заодно и сократить время на получение «одежды».
Когда ваши пользователи входят на ваш сайт через Google или подобный сервис, то пароль и сессия Google оказываются в браузере компьютера. Именно там, откуда их забирают программы-стилеры, а заражений ими в 2025 году стало на 59% больше. Это особенно опасно, если пользователь входит на ваш сайт с чужого или рабочего компьютера.
В статье я расскажу, как добавить на ваш сайт вход по QR-коду, когда пользователь сканирует код с компьютера телефоном и на телефоне выбирает учётную запись Google, Apple или Яндекс ID и подтверждает вход. И почему эта схема безопаснее и удобнее классической кнопки «Войти через Google».
О чем еще пойдет речь
Будет про passkey с телефона и OAuth Device Flow.
Коснусь QR-фишинга и того, что ему противостоит, и где у этой защиты предел.
Как дать вашему сайту или приложению удобный вход не только на компьютере или телефоне, но и на телевизоре, киоске с экраном или экране в переговорной.
В статье упоминается «Войти через Google», но в вашем приложении или сайте это может быть и «Войти через Yandex» или войти еще через что-то известное и большое, такое, что поддерживает OAuth и OpenID Connect. Поэтому то, что описано в статье, справедливо не только в отношении кнопки Google, но и любой другой подобной кнопки.
Начну с проблем.
Что остается в браузере после входа через Google
Ваш пользователь нажимает на сайте «Войти через Google». Кнопка открывает страницу Google в браузере его компьютера, и далее пользователь:
Вводит адрес почты.
Вводит пароль от Google, браузер может предложить его сохранить.
Подтверждает вход на телефоне или вводит код второго фактора.
Возвращается на ваш сайт.
OAuth и OpenID Connect здесь работают как задумано. Но после входа в профиле браузера лежит cookie сессии Google, а часто и сохраненный пароль. Рабочая сессия - это уже пройденный второй фактор, а значит с ней не нужен ни пароль, ни код с телефона. Можно открывать почту, файлы на Диске и все сайты, куда пользователь входит через Google.
Профиль браузера — это главная добыча стилеров. Это такие вредоносные программы, которые очень умело и порой изобретательно уносят сохраненные пароли и cookie из всех браузеров. Эксперты Kaspersky Digital Footprint Intelligence разобрали за 2025 год больше 5 млн логов стилеров с архивами украденных паролей, cookie и данными о системе. По их словам, число заражений стилерами за год выросло на 59%.
Но не всё так мрачно, как может показаться. С этим борются и, например, с мая 2026 года Chrome на Windows привязывает сессию Google к устройству: ключ лежит в TPM компьютера, а украденная cookie на другой машине не работает. Это, конечно, сильная защита, но узкая. Она не спасает пароль, который пользователь ввел и сохранил в браузере. Работает пока не везде, например для macOS защита ещё не вышла. И защищает только сессию Google, а не Apple или Яндекса.
Ваш сайт тут ни при чём, и стилер унес бы этот профиль и без вас. Но вход через Google на вашем сайте приучает пользователя вводить главный пароль на любом компьютере, где открыт ваш сайт. Хуже всего, если на чужом: в коворкинге, у клиента на встрече, в учебном классе, на рабочем ПК под чужим администратором. Там пользователь ничего не знает о том, что установлено, а если забудет выйти из Google, то следующий, кто будет за этим компьютером получит сессию пользователя без всякого стилера.

Что остаётся в браузере после обычной кнопки «Войти через Google»
Рассмотрим еще одну ситуацию. Она встречается гораздо реже, но встречается. Ваш сайт или приложение открыты на устройстве, где пароль набирать неудобно. Например: телевизор или ТВ-приставка, киоск с экраном, экран в переговорной. Пароль от Google на них пришлось бы вводить пультом или на экранной клавиатуре, у всех на виду.
Каким же образом в отрасли предлагается решать обозначенные проблемы?
Мессенджеры это уже решили, а passkey — наполовину
Например, Telegram Web и WhatsApp Web входят иначе. Компьютер показывает QR-код, пользователь сканирует его в приложении на телефоне, и компьютер получает сессию. Учётные данные остаются на телефоне, на компьютере вводить нечего. Наверняка некоторые из вас уже входили так в веб-версию мессенджера.
У Google и Apple есть похожий штатный способ, и это вход по passkey с другого устройства. Браузер компьютера показывает QR-код, пользователь сканирует его телефоном и подтверждает вход по Face ID или отпечатку. Пароль на компьютере не вводится, и это хорошо. Но, как обычно водится, не бывает всё хорошо и сразу. Какие у этого способа есть ложки дегтя:
Bluetooth должен быть на обоих устройствах. Телефон доказывает компьютеру, что он рядом, сигналом Bluetooth. У многих настольных ПК адаптера нет, а в компаниях Bluetooth на ПК нередко выключен политикой. Телевизоры и киоски такой вход обычно не поддерживают вовсе.
Ключ нужно завести заранее. У Apple тут всё очень даже хорошо: passkey для аккаунта Apple работает с iOS 17. А вот для Google — только если пользователь его создал или у него Android-телефон с этим аккаунтом: там Google может завести ключ сам. Я лично пробовал создавать passkey в Google и не скажу, что это был лучший пользовательский опыт.
У остальных провайдеров ключ сам не появляется. Apple и Google могут завести ключ к своему аккаунту, потому что им принадлежит система телефона. А вот ключ к аккаунту Яндекса, VK или другого провайдера, если тот вообще поддерживает passkey, есть только у того, кто уже зарегистрирован и сам завел его в настройках аккаунта.
Ну и главное. Сессия провайдера всё равно остаётся на компьютере. Passkey заменяет пароль, но вход выполняется в браузере компьютера, и cookie сессии Google или Apple оказывается в его профиле. И защищена она, только если её привязал к устройству браузер, как Chrome на Windows для Google.
Отдельная история про удалённый рабочий стол, а рабочий ПК сегодня часто именно такой. Браузер работает на удалённой машине, и passkey срабатывает, только если клиент пересылает запрос на компьютер пользователя. Такая пересылка есть, но с определенными ограничениями и кроме этого, в базовых настройках безопасности для RDP рекомендуется это отключать, что обычно системные администраторы и делают.
В этой статье я предлагаю рассмотреть еще один способ.
Это вход по QR-коду, как в мессенджере, но через аккаунт Google, Apple или Яндекса, собранный для своего сайта на стандартном OpenID Connect. Тогда вход у провайдера выполняется на телефоне, и сессия провайдера остаётся там же.
Далее я подробнее остановлюсь на нём и сравню его с passkey и Device Flow.
Как это выглядит для пользователя
Пользователь нажимает «Войти» на вашем сайте, и страница входа показывает QR-код.
Он сканирует код камерой своего телефона. Страница входа на компьютере сразу пишет, что QR-код отсканирован и подсказывает продолжить на телефоне.
Телефон открывает вход у провайдера (Google, Apple, Яндекс ID или другого). В свой аккаунт у провайдера на телефоне пользователь обычно уже вошёл, поэтому ему остается только выбирать учётную записью. На iPhone вход через Apple дополнительно подтверждается по Face ID или код-паролю.
На телефоне показывается страница подтверждения: в какое приложение пользователь входит, в каком браузере и системе начат вход и когда. И чтобы подтвердить вход, пользователь протягивает ползунок «Да» до конца, а чтобы отказаться, нажимает «Нет».
Компьютер, телевизор или киоск входит на сайт.

Вход по QR-коду через Google по шагам
Если пользователь открыл сайт на самом телефоне, то сканировать получается нечего и в этом случае он просто нажимает кнопку на странице входа, а дальше всё то же самое, что описано выше, пункты 3-5.
Сравним с кнопкой «Войти через Google»
В нашем случае:
На компьютере пользователь ничего не вводит: ни почту, ни пароль, ни код.
Bluetooth не нужен, хватит камеры телефона.
Выходить из Google на компьютере не нужно, потому что входа в Google на нём и не было, и в худшем случае стилеру на нём нечего взять, кроме сессии вашего сайта.
На телефоне пользователь только сканирует код, выбирает аккаунт и сдвигает ползунок. Это три простых действия без ввода. Ввод понадобится, только если на самом телефоне вход в Google или Apple еще не осуществлен.
В этой схеме есть и еще один не совсем очевидный плюс. Удобный вход в три быстрых простых действия устраняет необходимость задавать длинные сессии у приложений, а это, в свою очередь, тоже положительно влияет на безопасность вашего приложения.
Как это устроено
Между вашим сайтом и Google, Apple или Яндексом стоит свой OpenID Connect-провайдер. У нас это Veriqa — провайдер с открытым ядром на .NET и OpenIddict. Для вашего сайта Veriqa это обычный OIDC-провайдер с адресом discovery, client_id, секретом и адресом возврата. Его подключают штатным OIDC-плагином CMS или библиотекой фреймворка на том языке, на котором написан ваш сайт. Своего программного кода писать не надо. Генерацию QR-кода, вход у провайдера на телефоне и страницу подтверждения берёт на себя Veriqa.

Как устроен вход по QR-коду: диаграмма последовательности
Браузер компьютера открывает обычный вход OpenID Connect:
/connect/authorize, authorization code с PKCE. Veriqa показывает страницу входа с QR-кодом.Телефон открывает ссылку из QR-кода, получает необходимые данные для следующего действия.
Veriqa отправляет телефон к Google, Apple или Яндексу по потоку authorization code. Пользователь выбирает аккаунт.
Провайдер возвращает телефон на адрес возврата Veriqa. Veriqa проверяет ответ и показывает страницу подтверждения.
Пользователь подтверждает вход, браузер компьютера получает код авторизации.
Сайт обменивает код на токены OpenID Connect, как при любом другом входе.
Сайт получает те же стандартные токены OpenID Connect, что и от любого другого способа входа в Veriqa. sub имеет вид {канал}:{идентификатор у провайдера}, например yandex:1234567890, и рядом приходят claims провайдера.
Каждый провайдер дает свои claims, и они преобразуются в стандартные claims OpenID Connect.
Например:
Google дает идентификатор, полное имя, имя и фамилию, email, аватар, язык
Apple самый «скупой» и дает только идентификатор и email
Яндекс ID предоставляет идентификатор, имя пользователя, имя и фамилию, email, аватар, а если включить в настройках канала, то и телефон, и дату рождения

Что получает сайт при входе через Google
Так как Veriqa построена на базе OpenIddict, то вы можете подключить более 80 провайдеров OpenIddict (список) простой конфигурацией без кода. Одна конфигурация OAuth-клиента провайдера даёт один канал, а этот канал обслуживает все сайты и приложения, подключённые к вашей одной установке Veriqa. То есть регистрировать OAuth-клиента в Google для каждого вашего сайта заново не нужно.
Например, так выглядит конфигурация канала Яндекс ID:
{
"Veriqa": {
"Channels": {
"yandex": {
"Enabled": true,
"InboundVerification": "outbound_fetch",
"WebProvider": {
"Provider": "Yandex",
"ClientId": "0123456789abcdef0123456789abcdef",
"PublicBaseUrl": "https://id.example.com"
}
}
}
}
}
Идентификатор клиента в примере вымышленный. Права доступа - адрес почты, имя, портрет, Яндекс ID просит выбрать при регистрации приложения, поэтому scopes в конфигурации не нужны. Дополнительные, провайдер-специфичные, ключи указываются тут же. Секрет клиента держите в переменной окружения Veriqa__Channels__yandex__WebProvider__ClientSecret, а не в appsettings.json. Все ключи и их назначение можно посмотреть в документации Вход через аккаунт провайдера.
Раз используется QR-код, то нужно рассмотреть вопросы, связанные с безопасностью QR-фишинга. А раз есть возможность входа, кроме компьютера и на телевизоре, то нужно обязательно рассмотреть и отличия от Device Flow.
Чем это отличается от Device Flow
Тем кто не понаслышке знает OAuth 2.0 Device Authorization Grant (RFC 8628), эта схема покажется знакомым велосипедом. Телевизор показывает адрес и код, часто вместе с QR-кодом. Пользователь открывает адрес на телефоне, вводит код, входит у провайдера и разрешает доступ, а телевизор тем временем опрашивает провайдера, пока не получит токены. Такой поток есть, например, и у Google, и у Яндекс ID.
Сравните, чем вход через Veriqa лучше.
Удобнее для пользователя. В Device Flow у Google и Яндекса пользователь вводит код на телефоне вручную. У нас лишь сдвинуть ползунок.
Удобнее для разработчика. Device Flow обычно реализуют отдельно под каждого провайдера, если тот его конечно поддерживает. У нас ваш сайт подключен один раз к обычному входу через OIDC-клиента, и это работает на любой поверхности с браузером.
Безопаснее. Потому что устройство получает меньше. Device Flow выдает устройству токены провайдера, а с ними доступ к API в пределах scopes. Есть одна известная атака: злоумышленник сам начинает поток, присылает жертве код, например под видом приглашения на встречу, и жертва вводит его на настоящей странице провайдера. Так в 2024–2025 годах действовала группа Storm-2372, получая доступ к почте и файлам аккаунтов Microsoft 365 (Microsoft Security Blog). У нас сайт получает от Veriqa только идентичность пользователя. Токены провайдера до сайта не доходят, и Veriqa их не хранит. К тому же страница подтверждения показывает, где начат вход, а в Device Flow пользователь видит только код.
Device Flow остаётся правильным хардкорным выбором, если приложению нужен API провайдера, например календарь Google или YouTube. Тогда этот доступ приложение получает у провайдера само, своим входом. А в нашем продукте мы сознательно не получаем для приложения полноценный токен провайдера и не передаём его. Но никто не мешает вам сделать это самим, получив таким образом и удобство, и токен. Сделать можно обработчиком на клиенте OpenIddict встроенного канала или своим каналом по образцу из репозитория, подробнее в документации.
QR-фишинг. Главная атака на любой вход по QR-коду
Слабость у любого входа по QR-коду одна: пользователь не может проверить, чей перед ним код. Злоумышленник сам открывает вход на вашем сайте и подсовывает пользователю свой QR-код — на поддельной странице, в письме, в сообщении «отсканируйте, чтобы получить скидку». Пользователь сканирует, подтверждает, и сессия открывается у злоумышленника.
Это касается Telegram Web, WhatsApp Web и нашего входа тоже. В RFC 10027 (BCP 247), который IETF выпустил в 2026 году, атака называется Cross-Device Consent Phishing, и RFC прямо признаёт, что канал между устройствами не аутентифицирован и последнее слово за пользователем: дословно это звучит так «The only mitigation against this unauthenticated channel is the user’s judgment».
Какой максимальный ущерб для пользователя в нашем случае? Злоумышленник получает сессию на вашем сайте под аккаунтом пользователя. Но аккаунт Google или Яндекса ему не достаётся: токены провайдера до сайта не доходят, а Veriqa их не хранит. При фишинге через Device Flow он получил бы как раз токены провайдера, как в атаке Storm-2372 выше.
Что этой атаке противостоит:
Страница подтверждения называет, где начат вход. На ней приложение, браузер, система и время, и вход завершается только после ответа. Если пользователь сидит за Windows, а страница называет macOS, это повод нажать «Нет». Если подключить настройку GeoIP, то пользователю будет показываться и регион/город операции.
Ответ по умолчанию «Нет». Кнопка «Нет» выделена и в фокусе при открытии страницы, а «Да» на сенсорном экране принимается только сдвигом ползунка до конца. Случайным касанием вход не подтвердить.

Страница подтверждения входа на телефоне
Код живёт недолго и срабатывает один раз. Вход ждёт ответа 300 секунд по умолчанию, вход по ссылке из QR-кода завершается только один раз. Код из старого письма уже не сработает.
Повторный скан виден. Если ссылку из QR-кода открывают ещё раз в другом браузере, страница входа пишет: «QR-код отсканирован ещё на одном устройстве. Если это были не вы, начните заново».

Предупреждение о повторном сканировании QR-кода
Ответить может только тот, кто вошёл у провайдера. Страница подтверждения работает только в браузере телефона, который вернулся от провайдера. По её адресу из другого браузера не видно ни данных, ни кнопок, а ответ второго аккаунта для того же входа не принимается.
Сервер записывает, каким телефоном отсканирован код. По умолчанию это IP, браузер, система и тип устройства. Это не фактор входа, но сигнал риска для журнала и ваших проверок.
Предел у этой защиты есть. Если пользователь подтверждает, не читая, страница его не спасёт. Подтверждение на телефоне ничем не связано с браузером, где открывается сессия, поэтому такой вход, как и вход по QR-коду в мессенджерах, не устойчив к фишингу.
Чем отличается passkey
Passkey с другого устройства защищён лучше, но не всем, что о нём говорят. У него две защиты, и от разных атак. Нас интересует вторая.
Привязка к адресу — это защита от поддельного сайта. Ключ подписывает запрос только для того сайта, для которого создан, а адрес сайта подставляет браузер, а не страница. Если пользователь пришёл на двойник examp1e.com, браузер не предложит ему ключ от example.com, и подписывать нечего. Это закрывает классический фишинг, когда пользователь сам вводит данные на поддельной странице.
От пересылки QR-кода привязка к адресу не защищает. Злоумышленник открывает настоящий сайт в своём браузере, получает настоящий QR-код входа по passkey и показывает его жертве. Запрос в этом коде — к настоящему сайту, телефон честно предлагает войти туда, и подпись получается верной. Это та же атака, что и на наш вход.
Bluetooth — это защита от пересылки QR-кода. После скана QR-кода телефон шлёт сигнал Bluetooth, и браузер, показавший QR-код, должен его «услышать». Злоумышленник с настоящим QR-кодом сидит за своим компьютером далеко от жертвы, сигнала не слышит, и вход не завершается. Только эта проверка и мешает переслать QR-код по почте или показать его на поддельной странице.
НО если устройство злоумышленника в зоне Bluetooth, защиты от пересылки у passkey нет. Исследователь Деннис Книп показал такую атаку. Поддельная страница рисует окно Windows, похожее на системное, с QR-кодом от сервера атакующего, а запрос на подпись этот сервер берёт у настоящего сайта через прокси. Маячки Bluetooth рядом с жертвами — в офисе, кампусе, аэропорту — ловят сигнал телефона и пересылают его на этот сервер (разбор). Телефон спрашивает вход на настоящий сайт, пользователь подтверждает, и сессия достаётся атакующему. Bluetooth превращает дистанционную массовую атаку в целевую, с оборудованием рядом с жертвой, но не исключает её.
У нашего входа проверки близости нет. Пересланный QR-код сработает с любого расстояния, если пользователь подтвердит вход. Против этого у нас страница подтверждения, короткий срок жизни и предупреждение о повторном скане. Это меры, которые работают через внимание пользователя. По каждой из 17 мер защиты из RFC 10027 мы разобрали, что есть в Veriqa и чего нет, на странице Veriqa, BCP 247 и модель угроз. На нашем сайте и в документации мы рассматриваем несколько дополнительных проверок взамен проверки близости по Bluetooth, а также бесшовную интеграцию Veriqa и passkey.
Также стоит помнить и о том, что защита аккаунта равна защите самого слабого способа входа или восстановления, который ваш сайт оставил включённым. Поэтому, кроме добавления passkey, стоит поднимать и уровень самых слабых способов входа на ваш сайт. И passkey для вашего сайта кнопку Google не заменяет: ключ заводится у пользователя, который уже вошёл, а регистрацию, первый вход и восстановление всё равно нужно чем-то закрыть. Это и делает связка Veriqa и passkey, где первый вход и восстановление идут через Veriqa, а passkey добавляется поверх, что дает удобство ввода QR и уровень защиты passkey не только для нативных Google или Apple
В заключение еще раз о преимуществах входа по QR-коду
Удобство входа для пользователя и не нужна клавиатура. На телефоне пользователь обычно уже вошёл в свой аккаунт, и остаётся выбрать его.
Пароль лишний раз не вводится на уязвимом устройстве, таком как десктоп.
Короткие сессии на вашем сайте. Войти заново очень быстро и просто, поэтому сессию можно держать короткой и снизить риск утечек.
Малый возможный ущерб для пользователя. Сессию вашего сайта на компьютере стилер может унести, но это одна сессия одного сайта, а не весь аккаунт Google.
Вход вне экосистемы провайдера. Вход через Google работает на компьютере с macOS без входа в Google на нем.
Удалённый рабочий стол и виртуальные машины. QR-код на экране удалённого сеанса сканируется так же, как на обычном мониторе: радио и пробрасывание устройств не нужны.
Подтверждение действий. Тем же способом пользователь подтверждает действие на сайте, а не только вход. Например, повторный вход перед рискованной операцией (step-up).
Попробовать
Спасибо, что дочитали! Это моя первая статья на Хабре и мой первый открытый проект. Я вложил в него много времени, сил, эмоций и некоторое количество денег.
Открытым я его сделал потому, что сам в работе постоянно пользуюсь открытыми библиотеками, и хочу вернуть сообществу долг. Буду рад, если проект окажется полезным и вам. Попробуйте вживую, как выглядит вход по QR-коду через Google, Apple и Яндекс ID, и напишите в комментариях, что думаете. Буду рад любой обратной связи. И положительной, и отрицательной.
Посмотреть, как это выглядит на телевизоре, можно через браузер в эмуляторе вымышленного онлайн-кинотеатра Nova Stream.
Посмотреть, как это выглядит на обычном сайте, можно в онлайн-демо вымышленной поддержки вымышленной компании Helio.
Поиграть с разными настройками можно в онлайн-конструкторе на странице демо на veriqa.app.
Veriqa - OpenID Connect-провайдер для входа через MAX, Telegram, WhatsApp, другие мессенджеры, почту и аккаунты Google, Apple, Яндекса и других провайдеров.
Ядро открыто (MPL-2.0), сервер можно поставить у себя.

Комментарии 0