Проверка встраивания iframe
Бесплатный онлайн-инструмент проверки iframe: введите адрес любой веб-страницы, чтобы проверить её заголовки X-Frame-Options и Content-Security-Policy frame-ancestors, узнать, можно ли встроить страницу в iframe, и подтвердить это в реальном времени. История сохраняется только для текущей сессии браузера.
История (текущая сессия)
Сохраняется только во вкладке (sessionStorage); удаляется при закрытии вкладки. Никакие данные не отправляются на сервер.
Как работает проверка
- Введите целевой URL и нажмите «Проверить». Сервер запрашивает страницу как реальный запрос iframe (с Sec-Fetch-Dest: iframe) и считывает её заголовки ответа.
- Вердикт формируется на основе заголовков X-Frame-Options (DENY / SAMEORIGIN блокируют фрейминг) и Content-Security-Policy frame-ancestors (встраивание с любых сторонних сайтов разрешено только при указании * или универсального шаблона протокола).
- Тот же URL загружается в окно предпросмотра, чтобы вы могли убедиться в том, что делает браузер в реальности, включая срабатывания JavaScript frame-busting, которые скрыты в заголовках.
От чего зависит возможность встраивания страницы?
Решение о том, можно ли показывать веб-страницу внутри <iframe> на стороннем сайте, принимает браузер на основе заголовков ответа, отправляемых самой страницей. Данный инструмент выполняет аналогичную проверку на стороне сервера и выдаёт вердикт моментально.
X-Frame-Options — классический заголовок: DENY запрещает встраивание всех страниц, SAMEORIGIN разрешает его только со страниц из того же источника, а ALLOW-FROM удалён из современных браузеров. При отсутствии этого заголовка устаревшие правила не блокируют встраивание.
Content-Security-Policy: frame-ancestors — современная замена. Он указывает источники, которым разрешено встраивать страницу, например frame-ancestors 'self' https:\/\/example.com. Значение * (или просто протокол, например https:) разрешает встраивание любыми родителями по HTTPS; более узкие значения блокируют встраивание сторонними сайтами.
Одних заголовков недостаточно: скрипты на странице могут выполнять защиту от обмана фреймами (сравнивая top !== self и принудительно разрывая вложенность), а страницы авторизации или эндпоинты с геоограничениями могут реагировать иначе на запросы с датацентров. Именно поэтому к каждому результату прикреплён живой предпросмотр.
Быстрый справочник: настройка заголовков ответа
Если вы являетесь владельцем сайта, управляйте встраиванием напрямую через заголовки ответа.
Запретить встраивание с любой страницы
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Браузеры отказываются отображать страницу внутри любого iframe — это наиболее строгая защита от кликджекинга.
Разрешить встраивание только от источника того же домена
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Встраивать могут только страницы с той же схемой, хостом и портом; сторонние ресурсы будут заблокированы.
Разрешить встраивание только от конкретных источников
Content-Security-Policy: frame-ancestors 'self' https:\/\/trusted.example.com
Укажите доверенные источники в директиве frame-ancestors; все остальные будут заблокированы.
Разрешить встраивание с любой страницы
Не устанавливайте X-Frame-Options
Content-Security-Policy: frame-ancestors *
Любой сайт может встроить вашу страницу в iframe. Обязательно оцените компромиссы в области безопасности.
Примечание: X-Frame-Options устарел и заменён директивой CSP frame-ancestors. Если оба заголовка присутствуют, приоритет отдаётся CSP — рекомендуется использовать frame-ancestors.
Как сервер определяет, что запрос пришёл из iframe?
Примерно с 2020 года браузеры на базе Chromium и Firefox автоматически добавляют набор заголовков Fetch Metadata ко всем запросам навигации и загрузки подресурсов. Самый полезный для проверки встраивания — Sec-Fetch-Dest: он сообщает серверу, в каком контексте запрашивается ресурс, без какого-либо вмешательства запрашивающей страницы.
- Sec-Fetch-Dest: document — навигация верхнего уровня, вне любых фреймов.
- Sec-Fetch-Dest: iframe — запрос загружается внутри элемента <iframe>.
- Sec-Fetch-Dest: frame — загружается внутри устаревшего тега <frame> (фреймсета).
- Sec-Fetch-Dest: embed / object — загружается внутри элементов <embed> или <object>.
Данный чекер отправляет собственную проверяющую команду с заголовком Sec-Fetch-Dest: iframe, полностью повторяя запрос реального браузера при встраивании страницы. Таким образом, результат отражает, как целевой сервер действительно реагирует на легитимные запросы <iframe>, а не на обычный произвольный fetch.
Заголовок Sec-Fetch-Dest — это полезный индикатор, но не барьер безопасности: его поддерживают только современные браузеры. Небраузерные клиенты (curl, боты, некоторые WebView-контейнеры и устаревшие браузеры) могут игнорировать его полностью или передавать произвольные значения. Сервер может использовать этот заголовок для журналирования или применения лимитов запросов (rate-limit), однако ни в коем случае не стоит опираться на него в одиночку при оценке безопасности фрейминга. Окончательное решение о том, разрешено ли встраивание, по-прежнему принимают политики X-Frame-Options и CSP frame-ancestors, которые применяются самими браузерами независимо от наличия других заголовков.
Со стороны клиента страница может определить факт нахождения во фрейме даже без анализа заголовков, например сравнив window.top !== window.self (или проверив window.frameElement для страниц из одного источника), после чего предпринять действия: вывести предупреждение или принудительно открыть страницу в главном окне. Эта техника защиты от нежелательного фрейминга (frame-busting) была упомянута ранее, и она срабатывает независимо от содержимых заголовков запроса.
Примеры конфигурации сервера: блокировка встраивания в iframe
Приведённые ниже примеры показывают, как настроить каждый веб-сервер или фреймворк для полной блокировки встраивания в iframe (X-Frame-Options: DENY + CSP frame-ancestors 'none') — это самый строгий вариант из руководства выше.
server {
location / {
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none'" always;
}
}
<IfModule mod_headers.c>
Header always set X-Frame-Options "DENY"
Header always set Content-Security-Policy "frame-ancestors 'none'"
</IfModule>
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
next();
});
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'Content-Security-Policy', value: "frame-ancestors 'none'" },
],
},
];
},
};
class SetFrameOptions
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
$response->headers->set('X-Frame-Options', 'DENY');
$response->headers->set('Content-Security-Policy', "frame-ancestors 'none'");
return $response;
}
}
export default {
async fetch(request) {
const response = await fetch(request);
const headers = new Headers(response.headers);
headers.set('X-Frame-Options', 'DENY');
headers.set('Content-Security-Policy', "frame-ancestors 'none'");
return new Response(response.body, { status: response.status, headers });
},
};
Нужно разрешить встраивать страницу только вашему сайту или короткому списку доверенных источников, а не всем подряд? Замените DENY на SAMEORIGIN, а 'none' на 'self' или явный список источников — остальная конфигурация останется неизменной.
Известные особенности платформ
Отложив общие правила работы заголовков, отметим, что ряд популярных платформ имеет собственные специфические настройки. Прежде чем делать выводы о статусе «Заблокировано» или «Встраивается», опираясь исключительно на HTTP-заголовки, полезно учитывать эти нюансы.
| Платформа / сценарий использования | Поведение | Причина |
|---|---|---|
| Страница просмотра YouTube (youtube.com/watch) | Заблокировано | Вместо этого используйте официальный URL плеера youtube.com/embed/{id} — обычная страница просмотра применяет строгую политику фрейминга. |
| Страница объекта на картах Google | Заблокировано | К встраиванию предназначена только специальная ссылка iframe через Maps Embed API (google.com/maps/embed). |
| Страницы авторизации Google / Microsoft (OAuth) | Заблокировано | Целенаправленно заблокировано с 2015 года для предотвращения фишинга учётных данных во вкладках <iframe>; процесс авторизации должен выполняться в основном окне или всплывающем окне (popup). |
| Страницы оплаты (Stripe Checkout, PayPal, большинство банковских шлюзов) | Заблокировано | Встраивание формы оплаты — классический вектор атаки кликджекинга, поэтому платёжные процессоры блокируют это напрямую. |
| Страницы репозиториев и файлов GitHub | Заблокировано | Для всего сайта действует директива frame-ancestors 'none'; вместо <iframe> используйте REST/GraphQL API или сделайте скриншот. |
| Режим «Публикация в веб» для Notion / Google Документы | Встраивается | Созданы специально для встраивания: сам продукт предоставляет готовые сниппеты для этой цели. |
| Статьи в Википедии | Встраивается | По умолчанию не содержат ограничений X-Frame-Options или CSP, но перед масштабным встраиванием обязательно ознакомьтесь с условиями лицензии и правилами указания авторства. |
Типичные случаи использования
- Определите возможность встраивания стороннего виджета, панели управления или документа в ваш продукт ещё до начала написания кода интеграции.
- Проверьте, корректно ли ваш сайт отправляет запрошенные вами политики X-Frame-Options или CSP frame-ancestors.
- Диагностика защиты от кликджекинга: выясните, почему страница отображает `about:blank` или сообщение об отказе внутри iframe.
- Пакетная проверка потенциальных URL при агрегации контента или интеграции с порталом: используйте историю сеанса для возврата к результатам.
- Подготовьтесь к аудитам безопасности или тестированию на проникновение, задокументировав политику фрейминга внешних зависимостей.