Защита от clickjacking в браузерах: как настроить X-Frame-Options и расширения

Clickjacking закрывается не «антивирусом для браузера», а сочетанием двух вещей: правильного заголовка X-Frame-Options на вашем сайте и разумной защиты на стороне пользователя через расширения. Заголовок защищает всех посетителей, которые открывают сайт в современном браузере. Расширения помогают конкретному человеку не попасться на подмену клика, особенно в админках, банках и личных кабинетах.

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

Как браузер попадает в clickjacking

Сценарий обычно выглядит просто. Человек авторизован в личном кабинете, банке, CRM или админке. На другой странице злоумышленник встраивает этот кабинет в невидимый фрейм, а сверху рисует красивую кнопку: «Получить бонус», «Закрыть окно», «Подтвердить действие».

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

  • Атакующий не взламывает пароль.
  • Атакующий не обходит авторизацию.
  • Он просто использует уже открытую сессию пользователя.

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

Что делает X-Frame-Options

X-Frame-Options — это HTTP-заголовок ответа. Его отдаёт сервер, а браузер читает и решает, можно ли отображать страницу внутри <iframe>, <frame> или <object>.

Например, если страница отдаёт такой заголовок:

X-Frame-Options: SAMEORIGIN

браузер разрешит встроить её только на страницы с тем же origin: тот же протокол, домен и порт. Страница https://app.example.com сможет быть встроена только в https://app.example.com, но не в https://evil.example.

Основные варианты такие:

Директива Что разрешает Когда использовать Что помнить
DENY Запрещает встраивание вообще Личные кабинеты, админки, платёжные страницы, формы смены пароля Самый жёсткий вариант. Если вам нужны партнёрские iframe, он не подойдёт
SAMEORIGIN Разрешает встраивание только внутри того же сайта Сайты, где iframe нужны для своих же страниц Не защищает от вредоносного скрипта на том же origin
ALLOW-FROM uri Пытается разрешить один указанный origin Практически не стоит использовать как основное решение Плохо поддерживается современными браузерами. Для allowlist лучше CSP frame-ancestors

Если заголовка нет, браузер по умолчанию покажет страницу во фрейме. Именно поэтому пустая строка в response headers — это не «всё нормально», а зона риска.

Как выбрать политику для своего сайта

Начинайте не с копирования настройки из чужого блога, а с вопроса: «Эта страница вообще должна открываться внутри чужого сайта?»

Ситуация Что поставить Почему
Страница не должна быть встроена нигде X-Frame-Options: DENY Браузер не даст встроить её даже в ваш же сайт
Страницы можно встраивать только внутри вашего приложения X-Frame-Options: SAMEORIGIN Защита от чужих сайтов, но свои интерфейсы продолжают работать
Нужно разрешить встраивание на конкретном партнёрском сайте CSP frame-ancestors 'self' https://partner.example X-Frame-Options плохо подходит для точечного allowlist
Есть старые браузеры и партнёрские iframe Проверять связку CSP + X-Frame-Options Если поставить DENY, старые браузеры заблокируют даже разрешённые партнёрские сценарии
Вы обычный пользователь, а не владелец сайта Расширение с блокировкой фреймов/скриптов Вы не можете заставить чужой сайт отдавать нужный заголовок

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

Где именно ставить X-Frame-Options

Заголовок должен приходить в финальном HTTP-ответе страницы. Не в JavaScript, не в мета-теге, не «где-нибудь на фронтенде», а на сервере или на edge-уровне: nginx, Apache, IIS, CDN, reverse proxy, балансировщике, приложении.

Особенно проверяйте места, которые часто забывают:

  • страницы логина и восстановления пароля;
  • админ-панели;
  • платёжные и checkout-страницы;
  • ошибки 404, 403, 500;
  • мобильные версии;
  • ответы CDN и кэширующие прокси;
  • страницы, которые отдаются через отдельный сервис или микросервис.

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

Примеры настройки X-Frame-Options

Nginx

Для жёсткого запрета встраивания:

server {
    add_header X-Frame-Options "DENY" always;
}

Если разрешены только свои страницы:

server {
    add_header X-Frame-Options "SAMEORIGIN" always;
}

Ключ always полезен тем, что заголовок будет добавляться и к ответам с ошибками. Если у вас вложенные location со своими add_header, проверьте конфиг внимательнее: nginx может не наследовать заголовки так, как ожидается.

Apache

Нужен модуль mod_headers:

Header always set X-Frame-Options "SAMEORIGIN"

Или жёсткий вариант:

Header always set X-Frame-Options "DENY"

Node.js / Express

app.use((req, res, next) => {
  res.setHeader('X-Frame-Options', 'SAMEORIGIN');
  next();
});

Если используете helmet, не забудьте проверить, какая политика включена для frameguard. В больших проектах это часто всплывает при переезде: вроде защита есть, но в некоторых роутах она выключена или переопределена.

IIS

Через web.config:

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="X-Frame-Options" value="SAMEORIGIN" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

Как проверить, что браузер реально защищает страницу

Не ограничивайтесь тем, что «в конфиге написано». Проверьте ответ, который видит браузер.

  1. Откройте DevTools в браузере.
  2. Перейдите на страницу, которую хотите защитить.
  3. Во вкладке Network обновите страницу.
  4. Откройте ответ страницы и найдите X-Frame-Options.
  5. Проверьте не только 200 OK, но и ошибки.
  6. Создайте тестовую страницу с <iframe src="https://your-site.example/login"></iframe> и посмотрите, что покажет консоль.

Если защита работает, в консоли обычно будет сообщение в духе: Refused to display ... because it set 'X-Frame-Options' to 'SAMEORIGIN'. Это нормальная реакция браузера.

Дополнительно можно проверить через терминал:

curl -I https://your-site.example/login

Но curl показывает только сырой ответ сервера. Он не заменяет проверку в браузере, особенно если между сервером и пользователем стоят CDN, WAF или кэширующие прокси.

Почему расширения нужны, но не заменяют заголовок

Расширение помогает пользователю, но не защищает ваш сайт для всех посетителей. Если вы владелец сервиса, без серверного заголовка вы оставляете риск открытым.

У обычного пользователя нет кнопки «включить X-Frame-Options» в браузере. Браузер сам применяет этот заголовок, если сайт его отдаёт. Расширения же могут добавить второй слой защиты: блокировать сторонние фреймы, отключать скрипты, предупреждать о подозрительных кликах поверх скрытых элементов.

Что можно использовать:

Инструмент Что даёт против clickjacking Ограничения Кому подходит
NoScript Блокирует скрипты по умолчанию, есть механизмы защиты от подмены клика Требует настройки allowlist, иначе ломает часть сайтов Продвинутым пользователям и администраторам
uBlock Origin в расширенном режиме Может блокировать сторонние фреймы и запросы Это не специализированная кнопка «защитить от clickjacking», нужны правила Тем, кто уже использует блокировщик и готов разбираться
Корпоративные расширения для защиты веб-доступа Политики можно включить централизованно для сотрудников Нужны тесты, лицензии, совместимость с браузером Компаниям, где много сотрудников работают с админками и CRM

Не ставьте пять расширений «для безопасности» сразу. Каждое новое расширение получает широкие права в браузере. Лучше один понятный инструмент, регулярные обновления и проверенный источник установки.

Как настроить расширение без лишней головной боли

  1. Выберите один основной инструмент, а не набор случайных «антикликджекингов».
  2. Для рабочих задач заведите отдельный браузерный профиль: банк, админка, CRM — отдельно от обычного сёрфинга.
  3. Включите блокировку сторонних фреймов или скриптов хотя бы для чувствительных сайтов.
  4. Добавьте в исключения только те сервисы, где без iframe реально нельзя работать: платёжные виджеты, внутренние панели, доверенные интеграции.
  5. Проверьте сценарии: вход, отправка формы, смена пароля, оплата, экспорт отчёта.
  6. Если расширение ломает рабочий процесс, не отключайте защиту полностью. Настройте правило точнее.
  7. Для компании используйте централизованную установку через политики браузера, а не инструкцию «поставьте расширение сами».

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

Частые ошибки при защите от clickjacking

  • Ставят только расширение и не ставят заголовок. Это защищает только один браузер, а не всех пользователей сайта.
Оцените статью
PEFile — Безопасность и технологии простым языком