Пароли внутри iframe

Для обеспечения бесперебойной контекстной аутентификации в различных доменах организации часто встраивают страницы входа в систему в iframe. Однако загрузка контекстов аутентификации внутри сторонних фреймов подвергает пользователей серьезным угрозам, таким как кликджекинг (переопределение пользовательского интерфейса) и несанкционированное создание учетных данных. Для снижения этих рисков браузеры по умолчанию отключают WebAuthn в iframe, работающих в разных источниках. Безопасное снятие этого ограничения требует активных многоуровневых протоколов защиты .

Выявление моделей угроз

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

  • Отслеживание с помощью внедрения скрытого iframe: злоумышленник запускает запрос WebAuthn со своего собственного домена, используя рекламу или виджет на доверенном сайте, обманом заставляя пользователей авторизоваться с помощью пароля, не видя контекста. Это связывает личность пользователя с учетной записью, контролируемой злоумышленником, для сбора данных.
  • Визуальное наложение и кликджекинг (переделка пользовательского интерфейса): вредоносная родительская страница делает невидимым iframe аутентификации с помощью стандартных CSS и накладывает поддельный элемент пользовательского интерфейса, чтобы украсть клик, запускающий процесс аутентификации. Это может привести к перехвату сессии или принудительному выполнению несанкционированных действий, если пользователь случайно заполнит запрос.

Для противодействия этим угрозам следуйте этим передовым методам:

Для документа верхнего уровня (верхнего фрейма):

Для встроенного документа (iframe):

Для обоих документов:

Включите делегирование с помощью политики разрешений.

Браузеры по умолчанию блокируют доступ к WebAuthn в iframe, содержащих данные из разных источников. Политика разрешений — это единый механизм веб-платформы, позволяющий документу верхнего уровня явно делегировать эти мощные возможности конкретным, доверенным сторонним источникам.

Токены функций

WebAuthn использует два разных токена:

  • publickey-credentials-get : Предоставляет авторизацию для входа в систему с помощью пароля ( navigator.credentials.get() ).
  • publickey-credentials-create : Предоставляет авторизацию для процессов регистрации ключей доступа ( navigator.credentials.create() ).

Требования для обеспечения возможности

Для включения этих возможностей требуется согласование как в ответе родительского сервера, так и в разметке на стороне клиента:

Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")

Политика разрешений: совместимость с publickey-credentials-get:

Browser Support

  • Chrome: 88.
  • Край: 88.
  • Firefox: не поддерживается.
  • Safari: не поддерживается.

Source

Политика разрешений: совместимость с publickey-credentials-create:

Browser Support

  • Chrome: 88.
  • Край: 88.
  • Firefox: не поддерживается.
  • Safari: не поддерживается.

Source

  • Атрибут allow в HTML: В HTML-разметке элемент <iframe> также должен указывать, что он включает эту функцию.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>

Совместимость с iframe allow="publickey-credentials-get":

Browser Support

  • Chrome: 84.
  • Край: 84.
  • Firefox: 118.
  • Safari: не поддерживается.

Совместимость с iframe allow="publickey-credentials-create":

Browser Support

  • Chrome: не поддерживается.
  • Edge: не поддерживается.
  • Firefox: 123.
  • Safari: не поддерживается.

Включить разделенные сторонние файлы cookie

Для обеспечения надежного процесса аутентификации необходимо установить и поддерживать сессию внутри встроенного iframe, содержащего данные из других источников. Поскольку современные браузеры перешли к строгим ограничениям на использование сторонних файлов cookie, стандартные механизмы сохранения данных часто блокируются по умолчанию и могут потребовать вызова API доступа к хранилищу для получения доступа.

Для устранения этих препятствий настройте сессионные файлы cookie с атрибутами SameSite: None , Secure и Partitioned . Этот единый механизм платформы обеспечивает сохранение состояния внутри iframe, соблюдая при этом настройки конфиденциальности на уровне браузера.

Установить SameSite: None

SameSite: None явно помечает cookie для межсайтового доступа, позволяя отправлять его с запросами, сделанными из контекста стороннего ресурса (например, iframe). Этот атрибут является необходимым условием для корректной работы cookie в сценариях междоменного доступа, хотя для его принятия современными браузерами он должен сочетаться с атрибутом Secure .

Partitioned набор

Атрибут Partitioned позволяет использовать cookie-файл в режиме CHIPS (Cookies Having Independent Partitioned State) , что дает возможность хранить cookie-файл отдельно для каждого сайта верхнего уровня. Это гарантирует доступность cookie-файла в контексте конкретного iframe стороннего сервиса, обеспечивая сохранение состояния сессии без возможности отслеживания между сайтами. Пользователю придется повторно входить в систему для каждого встроенного элемента на другом сайте.

Защитите конечную точку с помощью политики безопасности контента (Content Security Policy).

В то время как политика разрешений определяет, может ли ваш iframe использовать WebAuthn, политика безопасности контента (CSP) определяет, кому разрешено размещать ваш iframe.

Для точки аутентификации крайне важно обеспечить, чтобы подфрейм входа в систему мог загружаться только на авторизованных партнерских сайтах или на ваших собственных ресурсах, предотвращая несанкционированные попытки кликджекинга еще до того, как они смогут загрузить пользовательский интерфейс.

Используйте frame-ancestors

Директива frame-ancestors определяет допустимые родительские страницы, на которые можно встраивать ваш сайт. Добавив домены в эту директиву, вы можете разрешить встраивание подфрейма входа в систему для определенных доменов.

Content-Security-Policy: frame-ancestors 'self' https://parent-site.example.com;

Политика безопасности контента: совместимость с предками фреймов:

Browser Support

  • Chrome: 40.
  • Край: 15.
  • Firefox: 58.
  • Сафари: 10.

Source

Установить X-Frame-Options

Устаревший заголовок X-Frame-Options поддерживает аналогичные возможности, но только бинарные параметры ( DENY или SAMEORIGIN ). Установите значения CSP frame-ancestors и X-Frame-Options: DENY если браузер не поддерживает CSP. Приоритет CSP всегда отдается тем, кто его поддерживает.

X-Frame-Options: DENY

Совместимость с X-Frame-Options:

Browser Support

  • Chrome: 4.
  • Край: 12.
  • Firefox: 4.
  • Сафари: 4.

Source

Доверяйте, но проверяйте на стороне сервера.

Клиентские проверки браузера оценивают намерения и разрешения, но сервер является окончательным арбитром доверия. Проверьте ответ на сервере проверяющей стороны (RP), чтобы убедиться в действительности и наличии подписи контекста.

Полезная нагрузка клиентских данных

Данные клиента WebAuthn включают параметры, специально разработанные для проверки контекста запроса, отправленного внутри iframe:

  • crossOrigin (логическое значение): указывает, был ли вызван API WebAuthn внутри iframe, находящегося в другом месте. Если ваша архитектура основана на iframe, ваш сервер должен обеспечить, чтобы этот флаг был установлен в true .
  • topOrigin (строка): Источник контекста верхнего уровня просмотра (то, что отображается в адресной строке браузера). Сервер должен проверить это по списку известных, авторизованных родительских источников.

Контрольный список проверки

Для проверки ответа аутентификатора на вашем сервере выполните следующие действия:

  1. Проанализируйте и декодируйте подписанные данные collectedClientData из ответа аутентификатора.
  2. Убедитесь, что type соответствует церемонии ( webauthn.get или webauthn.create ).
  3. Подтвердите присутствие пользователя и его подпись.
  4. Если запрос предназначался для отправки из iframe-структуры:
    • Enforce crossOrigin === true .
    • Убедитесь, что topOrigin соответствует вашему разрешенному списку родительских источников.

Устанавливайте безопасные сессии с помощью postMessage()

Для надежного установления сессии iframe должен передать токен аутентификации обратно на родительскую страницу с помощью postMessage() , позволяя родительской странице управлять состоянием сессии в собственном контексте.

Безопасный рабочий процесс

Для установления защищенного сеанса выполните следующие действия:

  1. Убедитесь, что URL-адрес src iframe содержит параметры запроса nonce и origin :
    • Используйте случайное значение для nonce . nonce служит токеном проверки безопасности, гарантирующим, что токен аутентификации, полученный от iframe, действительно соответствует конкретной сессии, инициированной родительской страницей.
    • В качестве origin используйте домен родительского фрейма. Параметр origin указывает источник родительской страницы, позволяя iframe безопасно идентифицировать авторизованный контекст, в который он встроен.
  2. iframe выполняет аутентификацию WebAuthn с помощью собственного сервера.
  3. Сервер iframe выдает токен, например JWT , который включает в себя nonce , и перенаправляет на родительскую страницу.

    // Extract nonce and origin from the URL params
    const urlParams = new URLSearchParams(window.location.search);
    const nonce = urlParams.get('nonce');
    const origin = urlParams.get('origin');
    if (!nonce || !origin) {
      alert('Nonce or origin is missing in the URL');
      return;
    }
    
    // Create a JWT
    const response = await post('/createToken', { nonce, origin });
    const token = response.token;
    
    // Post the JWT to the parent frame
    window.parent.postMessage({ token }, origin);
    
  4. Родительская страница отслеживает событие message , проверяет источник отправителя и подтверждает подлинность токена.

    window.addEventListener("message", (event) => {
      if (event.origin !== "https://embedded-auth.example.com") return;
      // Verify the received JWT
      const result = await post('/verifyIdToken', {
        token: event.data.token,
        origin: provider.origin,
      });
    });
    
  5. Если JWT-токен успешно подтвержден, родительская страница сохраняет сессию.

И отправитель, и получатель несут совместную ответственность за безопасность:

  • Отправитель (iframe): При отправке сообщений всегда указывайте строгий целевой источник (никогда не используйте "*" ).
  • Получатель (родитель): Всегда проверяйте event.origin при получении сообщений, чтобы предотвратить подмену источника.

Заключение

Безопасное использование iframe зависит от политики разрешений (Permissions Policy) для включения, политики конфиденциальности (CSP) для ограничения, разделенных сторонних файлов cookie для сохранения сессии, проверки контекста клиента на стороне сервера и передачи сессии с учетом контекста с помощью postMessage() .

Чтобы узнать больше по смежным темам, следите за блогом разработчиков Chrome от Google и изучите дополнительные ресурсы в документации Chrome Developer Identity .