Верификация возраста обманута за 30 секунд: анатомия провала

Верификация возраста обманута за 30 секунд: анатомия провала

В начале 2024 года Discord внедрил биометрическую верификацию возраста для доступа к NSFW-серверам. Twitch добавил проверку паспортов для mature контента. Snapchat сделал сканирование лиц обязательным для возрастных функций. Индустрия отчиталась перед регуляторами, родители успокоились, дети... продолжили делать что хотели.

Потому что всю эту «передовую систему защиты» можно обойти за 30 секунд. Без хакерских инструментов, без технических знаний, вообще без усилий. Достаточно открыть один сайт, нажать кнопку, отсканировать QR-код — и вы «совершеннолетний» во всех трёх сервисах одновременно.

Это не история про талантливого хакера. Это разбор архитектурного провала, который показывает, как миллионы биометрических данных собираются через систему безопасности с дырой размером с грузовик.

Как работает обход: техническая анатомия

Все три платформы используют одного провайдера верификации — британскую компанию Yoti. Архитектура классическая для identity federation: платформа генерирует session ID, перенаправляет пользователя на Yoti, там проходит биометрическая проверка, Yoti возвращает JWT-токен с результатом.

Схема напоминает OAuth, и должна работать по тем же принципам безопасности. Должна.

Проблема начинается с того, что Yoti использует один API endpoint для всех клиентов. Discord генерирует session, но ничто не мешает использовать этот session с Twitch. Токен верификации от Snapchat работает в Discord. Нет привязки токена к конкретному клиенту, нет валидации source, нет даже базового CSRF-механизма.

Разработчик под ником kibty создал инструмент age-verifier.kibty.town, демонстрирующий уязвимость. Механика простая:

  1. Сайт генерирует валидный Yoti session ID, используя публично доступный client_id Discord
  2. Подменяет параметры запроса, указывая контролируемый redirect_uri
  3. Пользователь сканирует QR-код в официальном приложении Yoti — проверка проходит легитимно
  4. Yoti возвращает JWT-токен с claim verified: true
  5. Инструмент передаёт токен в Discord API — платформа принимает результат без вопросов

Discord проверяет только валидность подписи токена и срок действия. Не проверяет issuer, не проверяет intended audience, не проверяет session binding. Если токен подписан Yoti — этого достаточно.

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

Где индустрия облажалась: архитектурные принципы

OAuth существует с 2006 года. OpenID Connect — с 2014. SAML — с начала 2000-х. За два десятилетия индустрия выработала чёткие паттерны secure federation. Yoti проигнорировал все.

Отсутствие client-specific session binding. Session ID должен быть криптографически привязан к конкретному клиенту через HMAC или asymmetric signing. При получении токена клиент проверяет, что session был создан именно им. Yoti этого не делает — session ID просто случайная строка без verification data.

Нет token audience validation. JWT спецификация определяет claim aud (audience) — для кого предназначен токен. Discord должен проверять aud: "discord", Twitch — aud: "twitch". Если не совпадает — отклонять. Yoti не включает audience в токены, платформы не проверяют.

Отсутствие nonce или challenge-response. Стандартная защита от replay attacks: клиент генерирует уникальный nonce при создании session, провайдер включает его в токен, клиент проверяет совпадение. Один токен — одна сессия. Yoti не использует nonce, токены можно переиспользовать.

Статичные, не секретные client_id. В OAuth client_id публичный, но используется вместе с client_secret для server-side validation. Yoti использует только client_id без дополнительной аутентификации. Любой может создать session от имени Discord, зная его client_id — а его можно извлечь из любого легитимного запроса через DevTools.

Игнорирование redirect_uri validation. OAuth требует strict matching redirect URI. Yoti проверяет только домен, не path. Можно указать https://attacker.com/callback вместо https://discord.com/age-verify — и Yoti отправит токен куда угодно.

Каждый из этих пунктов — базовая практика, описанная в RFC 6749 (OAuth), RFC 7519 (JWT), NIST SP 800-63 (Digital Identity Guidelines). Yoti внедрил биометрическую верификацию, но забыл про основы secure authentication.

В видео выше — полный технический разбор уязвимости с демонстрацией exploit flow, анализом JWT-токенов и объяснением, как должна работать правильная архитектура федеративной идентификации.

Последствия: не теоретическая уязвимость

Инструмент kibty публично доступен, не требует регистрации, работает из коробки. Любой может обойти age gate за полминуты, без технических навыков. Это не proof-of-concept для исследователей, это production-ready bypass для массового использования.

Discord позиционирует верификацию как защиту несовершеннолетних от NSFW-контента. Twitch использует для mature streams с насилием и откровенными темами. Snapchat — для возрастных фильтров и функций знакомств. Вся эта защита — театр безопасности.

Более того, пользователи проходят реальную биометрическую верификацию. Yoti собирает сканы лиц, фотографии документов, персональные данные. Огромная база PII (Personally Identifiable Information), хранящаяся для системы, которая не выполняет заявленных функций.

Юридические последствия. В ЕС действует GDPR, запрещающий сбор биометрических данных несовершеннолетних без строгого compliance. Если система верификации не работает — значит, платформы де-факто собирают данные детей, нарушая регуляции. Штраф до 4% годового оборота.

CCPA (California Consumer Privacy Act) требует обоснованной необходимости для сбора биометрии. Если верификация обходится одной кнопкой — какая обоснованность? Discord, Twitch, Snapchat — все имеют значительную аудиторию в Калифорнии.

UK Online Safety Bill вводит уголовную ответственность за предоставление доступа к harmful content несовершеннолетним. Если платформа заявляет о наличии age verification, но она не работает — это potential violation.

Как должно быть: правильная архитектура

Децентрализованная идентификация и zero-knowledge proofs — технологии, решающие проблему верификации без сбора биометрии. Пользователь создаёт криптографическое доказательство возраста на своём устройстве (используя правительственный ID с NFC-чипом или trusted hardware module), платформа проверяет proof без доступа к реальным данным.

Технологии существуют: zkSNARKs (zero-knowledge succinct non-interactive arguments of knowledge), verifiable credentials (W3C стандарт), self-sovereign identity frameworks. Но индустрия выбирает централизованные решения, потому что они дешевле интегрировать.

Для текущей архитектуры (централизованный провайдер) необходимо:

Session binding через HMAC. При создании session клиент генерирует secret key, отправляет HMAC(session_id, secret) провайдеру. Провайдер включает этот HMAC в токен. При получении токена клиент проверяет HMAC — если не совпадает, session был создан не им.

Обязательный audience claim в JWT. Токен должен содержать aud: "discord.com" и sub: "user_id". Discord проверяет: если aud не совпадает — reject. Это защищает от token reuse между платформами.

Challenge-response с временным nonce. Клиент генерирует криптографически случайный nonce, отправляет при создании session. Провайдер включает nonce в токен. Клиент проверяет совпадение и TTL (time to live). Один nonce используется один раз — защита от replay.

Client authentication через asymmetric keys. Вместо статичного client_id — использовать public key infrastructure. Клиент подписывает запрос на создание session приватным ключом, провайдер проверяет подписью через публичный ключ. Невозможно создать валидный session без доступа к приватному ключу.

Rate limiting и anomaly detection. Если один Yoti account используется для верификации на пяти платформах за минуту — флаг. Если session создаётся с IP в США, а токен приходит с IP в России — suspicious. Machine learning модели могут детектировать аномальные паттерны использования.

Всё это — стандарт в финтехе, healthcare, government identity systems. Yoti работает с платформами, обрабатывающими биометрию миллионов пользователей, но использует security practices уровня pet project.

Реакция индустрии: PR вместо патчей

Discord ответил на bug reports: «Мы знаем о проблеме и работаем с Yoti над исправлением». Классический non-statement: нет timeline, нет деталей, нет commitment.

Twitch не комментировал. Snapchat выпустил заявление: «Безопасность пользователей — наш приоритет, мы постоянно улучшаем системы». Zero конкретики.

Yoti заявил: «Мы обновили протоколы безопасности в ответ на сообщения исследователей». Но инструмент kibty продолжает работать спустя недели после публикации. Либо патч неэффективен, либо его вообще не было — только PR.

Это паттерн индустрии: vendor lock-in на третьесторонних провайдеров, zero transparency о внутреннем устройстве систем, reactive approach вместо proactive security design. Уязвимость становится публичной — компании пишут заявления. Exploit продолжает работать — компании молчат.

Сравните с финтехом: когда находят уязвимость в платёжной системе, патч выходит в течение часов, публикуется technical disclosure, проводится external audit. В соцсетях — PR-заявление и надежда, что пользователи забудут.

Выводы: театр безопасности вместо защиты

Age verification становится законодательным требованием по всему миру. UK Online Safety Bill требует верификацию для доступа к порнографии. EU Digital Services Act вводит возрастные ограничения для соцсетей. В США Луизиана, Юта, Арканзас уже приняли аналогичные законы.

Если индустрия будет внедрять биометрическую верификацию с такими архитектурными провалами — мы получим massive privacy disaster. Миллионы сканов лиц, паспортов, персональных данных в системах, которые ломаются за 30 секунд.

Родители думают, что дети защищены. Платформы отчитываются перед регуляторами о compliance. Регуляторы ставят галочки в чеклистах. А реальная защита — ноль.

Что делать разработчикам: если ваш продукт использует third-party verification — проведите security audit integration point. Проверьте token validation logic. Убедитесь, что JWT содержит необходимые claims (aud, sub, iat, exp, nonce) и они реально проверяются. Добавьте session binding. Реализуйте anomaly detection. Не доверяйте провайдеру только потому, что он «крупный».

Что делать пользователям: понимайте, что биометрическая верификация не гарантирует ни безопасности, ни privacy. Если платформа требует скан лица «для защиты детей» — спросите, кто провайдер, как хранятся данные, какова их breach history. Читайте privacy policy. Ищите альтернативы с decentralized identity.

Технологии для secure age verification существуют. Zero-knowledge proofs позволяют доказать возраст без раскрытия биометрии. Verifiable credentials дают пользователю контроль над данными. Self-sovereign identity исключает централизованных посредников.

Но индустрия выбирает дешёвые централизованные решения, собирающие максимум данных, с минимальными инвестициями в безопасность. Результат — системы, которые не выполняют заявленных функций, создают honeypots для хакеров, нарушают privacy и подставляют компании под регуляторные штрафы.

Пока инструменты вроде age-verifier.kibty.town работают публично, пока компании отвечают PR-заявлениями вместо патчей, пока провайдеры игнорируют базовые принципы secure federation — ничего не изменится.

Биометрическая верификация — это не галочка в compliance checklist. Это критическая инфраструктура, обрабатывающая самые чувствительные данные пользователей. И если её можно обойти за 30 секунд — это не система безопасности. Это театр.