Skip to content

Latest commit

 

History

History
219 lines (140 loc) · 14.4 KB

File metadata and controls

219 lines (140 loc) · 14.4 KB

Атака типа clickjacking

Атака типа clickjacking (англ. "захват клика") позволяет вредоносной странице кликнуть по сайту-жертве от имени посетителя.

Многие сайты были взломаны подобным способом, включая Twitter, Facebook, Paypal и другие. Все они, конечно же, сейчас защищены.

Идея

Идея этой атаки очень проста.

Вот как clickjacking-атака была проведена на Facebook:

  1. Посетителя заманивают на вредоносную страницу (неважно как).
  2. На странице есть ссылка, которая выглядит безобидно (например, "Разбогатей прямо сейчас" или "Нажми здесь, это очень смешно").
  3. Поверх этой ссылки вредоносная страница размещает прозрачный <iframe> с src с сайта facebook.com таким образом, что кнопка "like" находится прямо над этой ссылкой. Обычно это делается с помощью z-index в CSS.
  4. При попытке клика на эту ссылку посетитель на самом деле нажимает на кнопку.

Демонстрация

Вот как выглядит вредоносная страница. Для наглядности <iframe> полупрозрачный (на реальных вредоносных страницах он полностью прозрачен):

<style>
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="/clickjacking/facebook.html"></iframe>

<button>Нажмите сюда!</button>
*/!*

<div>...И всё будет супер (у меня, хакера)!</div>

Полная демонстрация атаки:

[codetabs src="clickjacking-visible" height=160]

Здесь у нас есть полупрозрачный <iframe src="facebook.html">, и в примере мы видим его висящим поверх кнопки. Клик на кнопку фактически кликает на ифрейм, но этого не видно пользователю, потому что ифрейм прозрачный.

В результате, если пользователь авторизован на сайте Facebook ("Запомнить меня" обычно активировано), то он добавляет "лайк". В Twitter это будет кнопка "читать", и т.п.

Вот тот же пример, но более приближенный к реальности с opacity:0 для <iframe>:

[codetabs src="clickjacking" height=160]

Всё, что нам необходимо для атаки — это расположить <iframe> на вредоносной странице так, чтобы кнопка находилась прямо над ссылкой. Так что пользователь, кликающий по ссылке, на самом деле будет нажимать на кнопку в <iframe>. Обычно это можно сделать с помощью CSS-позиционирования.

Эта атака срабатывает только на действия мыши (или аналогичные, вроде нажатия пальцем на мобильном устройстве).

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

Но есть одна проблема. Всё, что посетитель печатает, будет скрыто, потому что ифрейм не виден. 

Обычно люди перестают печатать, когда не видят на экране новых символов.

Примеры слабой защиты

Самым старым вариантом защиты является код JavaScript, запрещающий открытие страницы во фрейме (это называют "framebusting").

Выглядит он вот так:

if (top != window) {
  top.location = window.location;
}

В этом случае, если окно обнаруживает, что оно открыто во фрейме, оно автоматически располагает себя сверху.

Этот метод не является надёжной защитой, поскольку появилось множество способов его обойти. Рассмотрим некоторые из них.

Блокировка top-навигации

Мы можем заблокировать переход, вызванный изменением top.location, в обработчике события beforeunload.

Внешняя страница (принадлежащая хакеру) устанавливает на это событие обработчик, отменяющий действие браузера по умолчанию, например:

window.onbeforeunload = function() {
  return false;
};

Тогда при попытке ифрейма изменить top.location посетитель увидит сообщение с вопросом, действительно ли он хочет покинуть эту страницу. В большинстве случаев посетитель ответит отрицательно, поскольку он не знает об ифрейме: всё, что он видит - это верхнюю страницу, которую нет причин покидать. Поэтому top.location не изменится!

В действии:

[codetabs src="top-location"]

Атрибут "sandbox"

Одним из действий, которые можно ограничить атрибутом sandbox, является навигация. Соответственно ифрейм внутри sandbox не изменит top.location.

Поэтому мы можем добавить ифрейм с sandbox="allow-scripts allow-forms". Это снимет некоторые ограничения, разрешая при этом использование скриптов и форм. Но мы опускаем allow-top-navigation, чтобы изменение top.location было запрещено.

Вот код этого примера:

<iframe *!*sandbox="allow-scripts allow-forms"*/!* src="facebook.html"></iframe>

Есть и другие способы обойти эту простую защиту.

Заголовок X-Frame-Options

Заголовок X-Frame-Options со стороны сервера может разрешать или запрещать отображение страницы внутри фрейма.

Это должен быть именно HTTP-заголовок: браузер проигнорирует его, если найдёт в HTML-теге <meta>. Поэтому при <meta http-equiv="X-Frame-Options"...> ничего не произойдёт.

Заголовок может иметь 3 значения:

DENY : Никогда не показывать страницу внутри фрейма.

SAMEORIGIN : Разрешить открытие страницы внутри фрейма только в том случае, если родительский документ имеет тот же источник.

ALLOW-FROM domain : Разрешить открытие страницы внутри фрейма только в том случае, если родительский документ находится на указанном в заголовке домене.

Например, Twitter использует X-Frame-Options: SAMEORIGIN.

Вот результат:

```html
<iframe src="https://twitter.com"></iframe>
```

<!-- ebook: prerender/ chrome headless dies and timeouts on this iframe -->
<iframe src="https://twitter.com"></iframe>

В зависимости от того, какой браузер вы используете, `iframe` выше либо будет пустым, либо оповестит вас о том, что его невозможно отобразить.

Отображение с ограниченными возможностями

У заголовка X-Frame-Options есть побочный эффект. Другие сайты не смогут отобразить нашу страницу во фрейме, даже если у них будут на то веские причины.

Так что есть другие решения... Например, мы можем "накрыть" страницу блоком <div> со стилями height: 100%; width: 100%;, чтобы он перехватывал все клики. Этот <div> будем убирать, если window == top или если мы поймём, что защита нам не нужна.

Примерно так:

<style>
  #protector {
    height: 100%;
    width: 100%;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 99999999;
  }
</style>

<div id="protector">
  <a href="/" target="_blank">Перейти к сайту</a>
</div>

<script>
  // Здесь будет отображаться ошибка, если верхнее окно имеет другое происхождение
  // а здесь будет код, если всё в порядке
  if (top.document.domain == document.domain) {
    protector.remove();
  }
</script>

Демонстрация:

[codetabs src="protector"]

Атрибут cookie: samesite

Атрибут samesite также может помочь избежать clickjacking-атаки.

Файл куки с таким атрибутом отправляется на сайт только в том случае, если он открыт напрямую, не через фрейм или каким-либо другим способом. Подробно об этом - в главе info:cookie#samesite.

Если сайт, такой как Facebook, при установке авторизующего куки ставит атрибут samesite:

Set-Cookie: authorization=secret; samesite

... Тогда такие куки не будут отправляться, когда Facebook будет открыт в ифрейме с другого сайта. Так что атака не удастся.

Атрибут samesite не играет никакой роли, если куки не используются. Так что другие веб-сайты смогут отображать публичные, не требующие авторизации, страницы в ифрейме.

Однако, это даёт возможность в некоторых ситуациях осуществить clickjacking-атаку, например, на сайт для анонимных опросов, который предотвращает повторное голосование пользователя путём проверки IP-адреса. Он останется уязвимым к атаке, потому что не аутентифицирует пользователей с помощью куки.

Итого

Атака сlickjacking - это способ хитростью "заставить" пользователей кликнуть на сайте-жертве, без понимания, что происходит. Она опасна, если по клику могут быть произведены важные действия.

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

С одной стороны — эта атака "неглубокая", ведь хакер перехватывает только один клик. Но с другой стороны, если хакер знает, что после этого клика появятся другие элементы управления, то он может хитростью заставить пользователя кликнуть на них.

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

  • Для защиты от этой атаки рекомендуется использовать X-Frame-Options: SAMEORIGIN на страницах или даже целиком сайтах, которые не предназначены для просмотра во фрейме.
  • Или, если мы хотим разрешить отображение страницы во фрейме и при этом оставаться в безопасности, то можно использовать перекрывающий блок <div>.