Clickjacking — X-Frame-Options
Clickjacking — атака, при которой злоумышленник накладывает невидимый iframe с целевым сайтом поверх своей страницы, заставляя пользователя кликать по скрытым элементам. X-Frame-Options и CSP
frame-ancestorsзащищают от этого.
Зачем нужно
Без защиты пользователь может непреднамеренно подтвердить банковский перевод, удалить аккаунт или изменить права — думая, что кликает по безобидной кнопке на странице злоумышленника. Особенно опасно для банков, соцсетей и панелей управления.
Где используется
- Страницы с кнопками действий (оплата, удаление, смена пароля)
- OAuth-флоу и формы аутентификации
- Панели администратора и настроек аккаунта
Основной контент
X-Frame-Options (устаревший, но широко поддерживается)
# Запретить встраивание в iframe полностью
X-Frame-Options: DENY
# Разрешить только тому же origin
X-Frame-Options: SAMEORIGIN
CSP frame-ancestors (современный стандарт, приоритетнее)
# Полный запрет
Content-Security-Policy: frame-ancestors 'none';
# Только сам сайт
Content-Security-Policy: frame-ancestors 'self';
# Разрешить несколько доменов
Content-Security-Policy: frame-ancestors 'self' https://partner.example.com;
Express + helmet
const helmet = require('helmet');
app.use(helmet.frameguard({ action: 'deny' }));
// Или вручную, оба заголовка одновременно
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
next;
});
Nginx
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none'" always;
Пример атаки (для понимания угрозы)
<!-- Страница злоумышленника -->
<style>
iframe {
position: absolute; opacity: 0.01;
width: 900px; height: 700px; z-index: 999;
}
button.fake { position: absolute; top: 330px; left: 400px; }
</style>
<iframe src="https://bank.example.com/transfer?to=hacker&amount=5000"></iframe>
<button class="fake">Выиграй iPhone!</button>
Частые ошибки
- Использование только
X-Frame-Options: ALLOW-FROM— не поддерживается Chrome/Firefox - Применение заголовков только к главной странице, а не ко всем ответам
- Попытка защититься через JavaScript frame-busting — обходится атрибутом
sandboxна iframe - Отсутствие
alwaysв Nginx — заголовки не отправляются при ошибках 4xx/5xx
Связанные темы
- _MOC Безопасность
- Веб-безопасность -- зачем и обзор угроз
- WAF -- Web Application Firewall
- Security Code Review -- чек-лист