Страница не открывается в iframe: проверяем frame-ancestors и X-Frame-Options

Страница работает отдельно, но не показывается в iframe. Разбираем, какая сторона запрещает встраивание, где искать заголовок и как проверить исправление.

Если страница открывается отдельно, но внутри iframe показывает «refused to connect», сначала посмотрите точную причину в Console браузера. При сообщении о frame-ancestors или X-Frame-Options сервер может исправно отдавать HTML, а браузер — запрещать его встраивание.

Проверять нужно две стороны: кто разрешает разместить документ у себя и кто разрешает встроить сам документ. Ответ HTTP 200 не подтверждает, что виджет работает; исправление принимают на странице, где он должен появиться.

1. Найдите документ, который браузер отказался показать

Откройте DevTools → Network, включите Preserve log и перезагрузите страницу с iframe. Найдите запрос документа фрейма, затем сопоставьте его с сообщением в Console.

Зафиксируйте адрес родительской страницы, исходный src iframe, конечный URL после перенаправлений и статус ответа. Например, виджет мог перенаправить посетителя на страницу входа, у которой встраивание намеренно запрещено: изменение политики исходного URL тогда не поможет.

Если URL не открывается и в отдельной вкладке, сначала разберите сетевую ошибку, TLS или серверный ответ. Надпись «refused to connect» внутри рамки сама по себе не доказывает отказ TCP-соединения.

2. Определите, с какой стороны стоит запрет

frame-ancestors — в ответе встраиваемой страницы

Эта директива Content-Security-Policy перечисляет источники, которым разрешено встраивать документ. Значение 'none' запрещает встраивание, а 'self' ограничивает его собственным origin — сочетанием схемы, хоста и порта.

Условный пример для ответа страницы виджета:

Content-Security-Policy: frame-ancestors 'self' https://portal.example;

Здесь разрешён портал с указанным origin. Это фрагмент настройки: его нужно согласовать с действующей CSP, сохранив остальные ограничения, а не заменить всю политику одной строкой.

При вложенности «портал → оболочка → виджет» проверьте всех предков виджета: разрешения только для ближайшей оболочки недостаточно. Директива не наследует запрет из default-src и не работает через HTML-тег meta. Эти особенности описаны в справочнике frame-ancestors.

X-Frame-Options — тоже в ответе встраиваемой страницы

DENY запрещает показ в любом фрейме. SAMEORIGIN требует одинакового origin у документа и всех его предков; похожие имена доменов не делают их одним origin.

Устаревшее ALLOW-FROM не подходит для разрешения партнёрского домена в современных браузерах. Заголовок нельзя настроить атрибутом iframe или meta-тегом: см. X-Frame-Options.

При действующей CSP с frame-ancestors современные браузеры применяют её вместо X-Frame-Options. Это правило относится к принудительной политике, а не просто к отчётному заголовку Content-Security-Policy-Report-Only: спецификация CSP.

frame-src — в политике родительской страницы

Если Console называет frame-src, проверяйте CSP страницы, содержащей iframe. Она задаёт, откуда эта страница может загружать фреймы; при отсутствии frame-src браузер проверяет child-src, затем default-src. Разрешение со стороны виджета не отменяет запрет со стороны родителя. См. описание frame-src.

3. Найдите слой, который добавляет заголовок

В Network откройте Response Headers именно конечного документа. Для публичного URL можно отдельно посмотреть ответы GET:

curl -sS -L --max-redirs 5 -D - -o /dev/null 'https://widget.example/embed'

Адрес условный: замените его своим публичным URL без токенов. Команда показывает заголовки цепочки, но не выполняет браузерные политики и не повторяет авторизованную сессию.

Сравните фактический ответ с настройками приложения, веб-сервера и CDN. Если политика приходит несколько раз, добавление ещё одной разрешающей CSP не снимает ограничения другой: найдите и исправьте источник конфликта. После изменения проверьте свежий ответ без браузерного кэша и учтите кеширование на CDN.

4. Исправьте разрешение только для нужной интеграции

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

Если документ принадлежит внешнему сервису, используйте его официальный embed-адрес или согласуйте интеграцию с владельцем. Когда поставщик запрещает iframe, обычная ссылка на страницу может быть корректным решением; отключение защиты браузера посетителей не исправляет интеграцию.

Добавление Access-Control-Allow-Origin не отменяет frame-ancestors и X-Frame-Options. Если Console указывает на CORP или COEP, перейдите к диагностике ERR_BLOCKED_BY_RESPONSE: это другая ветка проверки.

5. Проверьте результат в исходном сценарии

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

Если документ уже появился, но авторизация или кнопки не работают, отдельно исследуйте cookie и sandbox: разрешение встраивания не гарантирует работоспособность приложения. На подконтрольном тестовом origin вне списка также проверьте, что нежелательное встраивание осталось запрещено.

Мониторинг Web-Puls помогает следить за доступностью публичного URL, но успешная HTTP-проверка не заменяет этот браузерный сценарий.

Если источник конфликтующих заголовков неясен, отправьте заявку на диагностику. Укажите публичные адреса родителя и виджета, текст ошибки, конечный URL и последние изменения; не передавайте cookie, пароли и ссылки с токенами. Специалист оценит вводные и согласует формат работ.

Проверьте свой сайт прямо сейчас

Введите адрес сайта: Web-Puls покажет HTTP-код, время ответа и базовую диагностику. Для постоянного контроля можно подключить мониторинг.

Нужна помощь с диагностикой ошибки?

Опишите симптомы в короткой заявке: URL, код ответа, время появления и что менялось перед сбоем. Специалист поддержки оценит задачу и предложит формат работ.