Принудительное размещение веб-страницы в iframe?

У меня есть HTML-страница, предназначенная для встраивания в другой веб-сайт.

С помощью директивы CSP Frame-Ancestors я могу ограничить, на каких страницах разрешено использовать iframe. Это не позволяет использовать iframe на неправильном сайте, что и является целью этой политики безопасности.

В моем сценарии я также хочу заблокировать загрузку этой страницы отдельно, потому что это не имеет смысла и сбивает с толку людей, пытающихся с ней взаимодействовать. Его следует использовать только в контексте iframe.

Насколько я могу судить, у CSP нет возможности заблокировать автономный запуск страницы. Он работает как белый список, поэтому я могу только разрешить больше iframe и ничего не запрещать.

До сих пор я нашел только решения на стороне клиента (например, это, которое использует JavaScript), чтобы обнаружить это в браузере и затем что-то сделать. Хотя это жизнеспособное решение, я предпочитаю уже заблокировать его на стороне сервера.

Я просмотрел заголовки запросов и обнаружил, что только при первом запросе «Referer:» кажется «пригодным для использования», но ненадежным.

Итак, мой вопрос: можно ли обнаружить/заблокировать эту серверную часть или есть ли способ заставить браузер заблокировать это (аналогично CSP)? Или маршрут JavaScript действительно единственный способ справиться с этим?

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

allesmoegliche 24.07.2024 11:43

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

Niels Basjes 24.07.2024 12:24
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
2
51
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если

window.parent === window

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

Шаги для реализации этого:

1. Убедитесь, что страница не загружает вашу фактическую структуру при GET.

Убедитесь, что на вашей странице есть правильный head, теги link, script и meta и пустой body.

2. Убедитесь, что ваш скрипт, встроенный в iframe, имеет обработчик postMessage.

Про postMessage читайте здесь. Пример с этой страницы:

window.addEventListener(
  "message",
  (event) => {
    if (event.origin !== "http://example.org:8080") return;

    // …
  },
  false,
);

Убедитесь, что внутри data вы передаете что-то, что проверяет отображаемую страницу, например токен, понятный вашему серверу.

3. Отправить запрос со страницы при получении токена на сервер

Итак, вы получили data, давайте убедимся, что вы отправили его на сервер и, если оно действительно, получите содержимое, которое вы хотели отобразить, и добавите его в body как innerHTML. Упрощенным решением было бы создать на вашем сервере одноразовый буквенно-цифровой токен (возможно, случайный текст), который связан с хостом страницы, на которую должен быть встроен ваш iframe, и как только ваш сервер получит этот запрос, проверьте, является ли токен существует и связан с конкретным хостом, который отправил вам хост, ответьте на запрос действительным содержимым (если токен действителен) или сообщением об ошибке (если токен недействителен) и, конечно же, удалите токен после проверки. , но прежде чем ответить.

4. Скрипт для встраивания родительской страницы

Реализуйте сценарий Javascript, который

  • будет встроен в страницы, которые встраивают вашу страницу в iframe
  • проверяет, существует ли iframe, и указывает на ожидаемое место
  • отправляет запрос на сервер, запрашивая токен
  • запускает событие сообщения, ориентируясь на вашу страницу iframe и передавая токен (вызовите postMessage и передайте действительные данные, включая токен)

Спасибо за предложения по тому, как сделать это с помощью JavaScript. Мой основной вопрос: возможно ли сделать серверную часть; т.е. без какого-либо кода на стороне клиента (например, JavaScript).

Niels Basjes 24.07.2024 12:26

@NielsBasjes Нет, на стороне сервера это невозможно.

jabaa 24.07.2024 12:29

@NielsBasjes нет, запрос, отправляемый из iframe, представляет собой запрос GET для отправки на сервер, и не будет различий между отправкой из iframe или за пределами всех iframe.

Lajos Arpad 24.07.2024 14:31

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

Niels Basjes 24.07.2024 14:39

Пользователи @NielsBasjes могут скопировать исходный код iframe в память и вставить его в браузер или окно чата для кого-то другого. Пожалуйста, подумайте об этом сценарии и о том, подходит ли он для вашего варианта использования. Если вы по-прежнему предпочитаете описанный вами подход, возможно, вы захотите, чтобы запросы на публикацию принимались только после установления сеанса. Это предотвратит загрузку ее в качестве главной страницы, но новая проблема будет заключаться в том, что в следующий раз, когда вы вставите ее в iframe, у вас будет другой iframe, поэтому вам нужно будет каким-то образом уничтожить и воссоздать сеанс.

Lajos Arpad 24.07.2024 14:45

И именно так я и хочу: тот же iframe на отдельном сайте — это отдельная сессия. Ограничение всего этого запросами POST в некоторых случаях также может быть вариантом дополнения к этому. Спасибо.

Niels Basjes 24.07.2024 15:21

@NielsBasjes рад помочь. Дайте мне знать, намерены ли вы принять свой ответ или мою отредактированную версию.

Lajos Arpad 24.07.2024 15:23

Я нашел способ сделать это, который работает только с современными браузерами (достаточно хорош для меня) и работает в моем конкретном контексте.

Почему и как это работает в моем контексте:

  • мой iframe получает определенные значения в первом запросе со страницы, на которой он находится в iframe (набор параметров запроса в URL-адресе).
  • мое приложение iframed затем сохраняет это в сеансе (я выполняю весеннюю загрузку с использованием Kotlin), а идентификатор сеанса сохраняется в виде файла cookie в браузере.
  • при следующем взаимодействии в этом iframe данные сеанса видны и, таким образом, позволяют выполнить следующие шаги.

Проблема в том, что если ПОСЛЕ того, как вы это сделали (т. е. существует файл cookie с активным сеансом), а затем откройте URL-адрес iframed в отдельном окне вне ситуации iframed; это будет работать (чего я не хочу).

Пробуя что-то, я заметил сообщение в консоли браузера

  • Хром: Third-party cookie will be blocked in future Chrome versions as part of Privacy Sandbox..
  • Край: Third-party cookie will be blocked in future Microsoft Edge versions as part of unpartitioned third-party cookie deprecation.

Итак, я немного покопался в этом разделении, и оказалось, что если файл cookie разделен, то у него будет отдельная область действия внутри и снаружи iframe.

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

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

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

На основании этого https://github.com/spring-projects/spring-framework/issues/31454#issuecomment-1905442337 Теперь у меня это есть в моем (котлин) коде, и у меня есть то, что я хотел.

@Bean
fun forceAllCookiesToBePartitioned(): TomcatContextCustomizer {
    val cookieProcessor = Rfc6265CookieProcessor()
    cookieProcessor.partitioned = true

    return TomcatContextCustomizer { context: Context ->
        context.usePartitioned = true
        context.cookieProcessor = cookieProcessor
    }
}
Ответ принят как подходящий

Самый простой вариант — поискать заголовок и значение запроса:

Sec-Fetch-Dest: iframe

Я протестировал это на последних версиях Chrome, Edge, Firefox и Safari, которые охватывают всю мою группу пользователей.

Я могу легко проверить наличие этого значения и предоставить страницу с ошибкой, если оно отсутствует.

Другие вопросы по теме