Атака "кликджекинг" (англ. Clickjacking) позволяет хакеру выполнить клик на сайте-жертве от имени посетителя.
В русском языке встречается дословный перевод термина clickjacking: "угон клика". Так же применительно к clickjacking-атаке можно встретить термины "перекрытие iframe" и "подмена пользовательского интерфейса".
Кликджекингу подверглись в своё время Twitter, Facebook , PayPal, YouTube и многие другие сайты. Сейчас, конечно, они уже защищены.
В целом идея очень проста.
Вот как выглядел "угон клика" пользователя, который зарегистрирован на Facebook:
- На вредоносной странице пользователю подсовывается безобидная ссылка (скажем, что-то скачать, "разбогатеть сейчас", посмотреть ролик или просто перейти по ссылке на интересный ресурс).
- Поверх этой заманчивой ссылки помещен прозрачный iframe со страницей facebook.com, так что кнопка "Like" находится чётко над ней.
- Кликая на ссылку, посетитель на самом деле нажимает на эту кнопку.
Вот пример вредоносной страницы (для наглядности iframe
-- полупрозрачный):
<style>
iframe { /* iframe с сайта-жертвы */
width: 400px;
height: 100px;
position: absolute;
top:0; left:-20px;
*!*
opacity: 0.5; /* в реальности opacity:0 */
*/!*
z-index: 1;
}
</style>
<div>Нажмите, чтобы разбогатеть сейчас:</div>
<!-- URL в реальности - с другого домена (атакуемого сайта) -->
*!*
<iframe src="facebook.html"></iframe>
<button>Жми тут!</button>
*/!*
<div>..И всё получится (хе-хе, у меня, злого хакера, получится)!</div>
В действии:
[codetabs src="clickjacking-visible" height=200]
Так как <iframe src="facebook.html">
полупрозрачный, то в примере выше легко видеть, как он перекрывает кнопку. При клике на "Жми тут" на самом деле происходит клик на <iframe>
(на "Like").
В итоге, если посетитель авторизован на facebook (а в большинстве случаев так и есть), то facebook.com получает щелчок от имени посетителя.
На Twitter это была бы кнопка "Follow".
Тот же самый пример, но ближе к реальности, с opacity:0
для <iframe>
. Вообще незаметно, что на самом деле посетитель кликает на <iframe>
:
[codetabs src="clickjacking" height=200]
Итак, все, что нужно для проведения атаки -- это правильно расположить iframe на вредоносной странице, так чтобы кнопка с Facebook оказалась над "Жми тут!". В большинстве случаев это возможно и делается обычным CSS-позиционированием.
Атака называется "Clickjacking", то есть "угон клика", так как события клавиатуры "угнать" гораздо труднее.
Посетителя можно заставить сфокусироваться на `<input>` прозрачного `<iframe>` с сайтом-жертвой, но этот `<input>` невидим, а значит текст в нём также будет невидимым. Посетитель начнёт печатать, но, не увидев текст, прекратит свои действия.
Самый старый метод защиты -- это код JavaScript, не позволяющий отобразить веб-страницу внутри фрейма ("framebusting", также его называют "framekilling" и "framebreaking").
Примерно такой:
if (top != window) {
top.location = window.location;
}
То есть, если окно обнаруживает, что оно загружено во фрейме, то оно автоматически делает себя верхним.
Увы, в настоящий момент это уже не является сколько-нибудь надежной защитой. Есть несколько способов обхода framebusting. Давайте рассмотрим некоторые из них.
Можно заблокировать переход, инициированный сменой top.location
, в событии onbeforeunload.
Обработчик этого события ставится на внешней (хакерской) странице и, при попытке iframe
поменять top.location
, спросит посетителя, хочет он покинуть данную страницу. В большинстве браузеров хакер может спросить посетителя, используя своё сообщение.
window.onbeforeunload = function() {
window.onbeforeunload = null;
return "Хотите уйти с этой страницы, не узнав все её тайны (хе-хе)?";
}
Так что, скорее всего, посетитель ответит на такой странный вопрос отрицательно (он же не знает про ифрейм, видит только страницу, причины для ухода нет). А значит, ожидаемая смена top.location
не произойдёт!
Пример в действии:
[codetabs src="top-location"]
Современные браузеры поддерживают атрибут sandbox
Он позволяет разрешить во фрейме скрипты allow-scripts
и формы allow-forms
, но запретить top-навигацию (не указать allow-top-navigation
).
"Защищённый" <iframe>
хакер может подключить, к примеру, так:
<iframe *!*sandbox="allow-scripts allow-forms"*/!* src="facebook.html"></iframe>
Есть и другие приёмы для обхода этой простейшей защиты.
Firefox и старый IE могут активировать designMode на исходной странице, это также предотвращает framebusting, у IE есть нестандартный атрибут security для ифреймов, который можно использовать с той же целью.
Как мы видим, эта защита не только не выдерживает реальной атаки, но и может скомпрометировать сайт (программист-то думает, что защитил его).
Все современные браузеры поддерживают заголовок X-Frame-Options
.
Он разрешает или запрещает отображение страницы, если она открыта во фрейме.
Браузеры игнорируют заголовок, если он определен в МЕТА теге. Таким образом, <meta http-equiv="X-Frame-Options"...>
будет проигнорирован.
У заголовка может быть три значения:
SAMEORIGIN : Рендеринг документа, при открытии во фрейме, производится только в том случае, когда верхний (top) документ -- с того же домена.
DENY : Рендеринг документа внутри фрейма запрещён.
ALLOW-FROM domain : Разрешает рендеринг, если внешний документ с данного домена (не поддерживается в Safari, Firefox).
К примеру, Twitter использует X-Frame-Options: SAMEORIGIN
. Результат:
<iframe src="https://twitter.com"></iframe>
В зависимости от браузера, iframe
выше либо пустой, либо в нём находится сообщение о невозможности отобразить его (IE).
Заголовок X-Frame-Options
имеет неприятный побочный эффект. Иногда поисковики, анонимайзеры или другие сайты хотели бы отобразить страницу в iframe
, по вполне "легальным" причинам, но не могут.
Хорошо бы показывать их посетителям не пустой iframe
, а нечто, что может быть более интересно.
Например, можно изначально "накрывать" документ div
с height:100%;width:100%
, который будет перехватывать все клики. И поставить на нём ссылку, ведующую на страницу в новом окне.
<style>
#iframe-protector {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 99999999;
}
</style>
<div id="iframe-protector">
<a href="/" target="_blank">Перейти на сайт</a>
</div>
<script>
if (top.document.domain == document.domain) {
убрать iframe - protector
}
</script>
Если страница -- не во фрейме или домен совпадает, то посетитель не увидит его.
Атаку "Clickjacking" легко осуществить, если на сайте есть действие, активируемое с помощью одного клика.
Злоумышленник может осуществить атаку целенаправленно на посетителей ресурса -- опубликовав ссылку на форуме, или "счастливой рассылкой". Существует масса вариантов.
С первого взгляда, она "неглубокая": всё, что можно сделать -- это один клик. С другой стороны, если хакер знает, что после клика появляется какой-то другой управляющий элемент, то он, хитрыми сообщениями, может заставить посетителя кликнуть и по нему. А это уже не один, а два клика.
Атака особенно опасна, поскольку, проектируя интерфейс сайта, обычно никто и не задумывается о том, что клик от имени юзера может сделать хакер. Точки уязвимости могут быть в совершенно непредсказуемых местах.
- Рекомендуется использовать
X-Frame-Options
на страницах, заведомо не предназначеных для запуска во фрейме и на важнейших страницах (финансовые транзакции). - Используйте перекрывающий
<div>
, если это допустимо вашим проектом и вы хотите разрешить безопасный показ документа во фреймах с любых доменов.