Рамка Buster Buster… потрібен код Buster


422

Скажімо, ви не хочете, щоб інші сайти "обрамляли" ваш сайт у <iframe>:

<iframe src="http://example.org"></iframe>

Таким чином, ви вставляєте JavaScript на рамки, що перемикає рамки, на всі ваші сторінки:

/* break us out of any containing iframes */
if (top != self) { top.location.replace(self.location.href); }

Відмінно! Тепер ви автоматично «вибиваєтесь» або вириваєтесь із будь-якого містяться iframe. За винятком однієї невеликої проблеми.

Як виявилося, ваш код , що перебуває у кадрі, може бути розбитий , як показано тут :

<script type="text/javascript">
    var prevent_bust = 0  
    window.onbeforeunload = function() { prevent_bust++ }  
    setInterval(function() {  
      if (prevent_bust > 0) {  
        prevent_bust -= 2  
        window.top.location = 'http://example.org/page-which-responds-with-204'  
      }  
    }, 1)  
</script>

Цей код виконує наступне:

  • збільшує лічильник щоразу, коли браузер намагається перейти подалі від поточної сторінки через window.onbeforeunloadобробник подій
  • встановлює таймер, який спрацьовує кожну мілісекунду через setInterval(), і якщо він бачить лічильник посиленим, змінює поточне місцезнаходження на сервер управління зловмисником
  • цей сервер обслуговує сторінку з кодом статусу HTTP 204 , що не призводить до того, що браузер нікуди не рухається

Моє запитання - і це скоріше головоломка JavaScript, ніж реальна проблема - як ви можете перемогти перетворювач кадрів?

У мене було кілька думок, але в моєму тестуванні нічого не вийшло:

  • спроба очистити onbeforeunloadподію onbeforeunload = nullне дала ефекту
  • додавши alert()зупинений процес, дайте користувачеві знати, що це відбувається, але жодним чином не втручався в код; натискання кнопки "ОК" дозволяє продовжувати зйомки як завжди
  • Я не можу придумати жодного способу очистити setInterval()таймер

Я не дуже програміст JavaScript, тому ось моє завдання перед вами: ей, Бастер, чи можете ви перебити каркас?


6
Я не впевнений, що справжній працівник кадру дійсно працює ... коли я намагаюся його перевірити (перенаправлення на обробник, який я налаштував, щоб повернути 204), це заважає мені переходити кудись поза сторінкою - включаючи введення матеріалів в адресному рядку! Мені потрібно закрити вкладку браузера та відкрити нову, щоб дістатися куди завгодно. Тобто іншими словами, я не впевнений, що це потребує рішення, тому що кадр-перебірщик, який хоче бути розбитий, є ... розбитим для початку. :) (Або це, або я накрутив свій тест, що ніколи не могло трапитися ...);)
Метт Вінклер

16
Метт, розміщений вище код фрейм-бустер-бустер, безумовно, працює. А .. е .. приятель .. мій .. розповів мені .. про це. Або щось. :)
Джефф Етвуд

10
Джефф, ти тестуєш обидва вікна в одному домені? Схоже, що ти є, тому що якби ти не був, тоді обмеження безпеки заважали б вам змінити "onBeforeUnload"
Джеймс

29
Зі сторони: При розміщенні прикладів, будь ласка, використовуйте такі домени, як example.orgзазначено в RFC 2606 ietf.org/rfc/rfc2606.txt
Крістоф

3
Щодо загальної теми контрзаходів: galactanet.com/comic/view.php?strip=209
Joey

Відповіді:


149

Я не впевнений, чи це життєздатно чи ні - але якщо ви не можете зламати кадр, чому б просто не показати попередження. Наприклад, якщо ваша сторінка не є "верхньою сторінкою", створіть метод setInterval, який намагається зламати кадр. Якщо після 3 або 4 спроб ваша сторінка все ще не є верхньою сторінкою - створіть елемент div, який охоплює всю сторінку (модальне поле) з повідомленням і посиланням, як ...

Ви переглядаєте цю сторінку в несанкціонованому вікні кадру - (бла-бла ... потенційна проблема безпеки)

натисніть це посилання, щоб усунути цю проблему

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


2
Я спробував це, і це працює. Ще один твір, який мені подобається в цьому рішенні, - це те, що він розкриває користувачеві, на якому веб-сайті він / вона був, перш ніж перейти до вашого вмісту. Приклад коду: якщо (parent.frames.length> 0) {top.location.replace (document.location); setTimeout (function () {if (parent.frames.length> 0) {document.location = " google.com ";}}, 10); }
папа

Це не лише хороший спосіб уникнути зловживань, він досить привітний для сайтів, які можуть захотіти заробити ваш сайт просто для того, щоб зазирнути на нього, хоча і не допустити його використання. В ідеалі, я думаю, що слід використовувати скріншот домашньої сторінки сайту, де можна пояснити, чому його не можна використовувати в накладеній вершині iframe.
wheresrhys

33
Ось як це робить Facebook.
shamittomar

2
але, можливо, це може бути використане, якщо сайт, що перешкоджає, в свою чергу створить помилкове анти-анти-анти ... (не знаю, скільки анти ми зараз є) lighbox div для себе, представляючи фішинг-посилання або що завгодно ... tbc
yunzen

7
Ще одна ідея полягала б у тому, щоб просто стерти сторінку з чимось на зразок document.write("");(після того, як ви встановите, що вона оформлена
gabeio

211

6
Відмінно, підтримка цього в браузері .exe - це безперечно. Коли ви кажете "більшість браузерів", які саме? Я не можу знайти хороших джерел для нічого, крім IE8.
Джефф Етвуд

2
Ось тестова сторінка: Improie.com/test/clickjack . Підтримує Chrome 4.1.249.1042. Підтримка Opera 10.50. Firefox 3.6.2 ще не підтримує. Підтримка Safari 4.0.3.
EricLaw

1
Firefox 3.6.9 підтримуватиме його на власному рівні ( hackademix.net/2010/08/31/… ), а будь-яка установка Firefox з NoScript має його з початку 2009 року ( hackademix.net/2009/01/29/x-frame- options-in-firefox )
ssokolow

4
Найкраще поєднувати це з фреймбустером javascript.
Джессі Вайгерт

1
Або поєднати це з грудня '12 відповідь на цій сторінці: stackoverflow.com/a/13708510/328397
goodguys_activate

34

Ми використовували такий підхід на одному з наших веб-сайтів з http://seclab.stanford.edu/websec/framebusting/framebust.pdf

<style>
 body { 
 display : none   
}
</style>
<script>
if(self == top) {
document.getElementsByTagName("body")[0].style.display = 'block';
}
else{
top.location = self.location;
}
</script>

3
Бінго! Не впевнений, чому це не підтримується більше, оскільки це найкраща відповідь (поруч із відповіддю на параметри X-Frame, але найкраще поєднувати обидва)
Джессі Вайгерт

1
Цю відповідь чи мою слід вибрати :)

Мені подобається ваша ідея використовувати як це, так і параметри X-Frame: відхилити відповідь.
Макс Вест

Для цього потрібен JS, що є досить великим тягарем IMHO.
Навін

1
+1 - це найкраща відповідь, коли не можна використовувати X-FRAME-OPTIONS. (Наприклад, коли вам потрібно умовно дозволити або заборонити залежно від рефератора.)
Джей Салліван

29

Придумав це, і, здається, працює принаймні у Firefox та браузері Opera.

if(top != self) {
 top.onbeforeunload = function() {};
 top.location.replace(self.location.href);
}

2
і рішення Яні, і Джеффа (колись відредаговані) є правильними і працюють рівнозначно; давши Джані прийняти, оскільки його рішення спрацювало правильно, без редагування
Джефф Етвуд

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

Якщо є вкладені кадри, вам доведеться пройтися по ланцюжку кадрів і видалити всі onbeforeunloadобробники, не тільки той, що зверху!
Крістоф

12
важливе уточнення: це спрацювало для мене, тому що iframe src = встановлювався динамічно, і, таким чином, політика між домену НЕ діяла. JP абсолютно вірно, в статичному src = це не працює.
Джефф Етвуд

5
ОК зараз, може хтось придумує кадрувальницьку оброблювальну групу "
Епага

23

Враховуючи поточний стандарт HTML5, який запровадив пісочну скриньку для iframe, усі коди перебору кадрів, що надаються на цій сторінці, можна відключити, коли зловмисник використовує пісочницю, оскільки це обмежує iframe від наступного:

allow-forms: Allow form submissions.
allow-popups: Allow opening popup windows.
allow-pointer-lock: Allow access to pointer movement and pointer lock.
allow-same-origin: Allow access to DOM objects when the iframe loaded form same origin
allow-scripts: Allow executing scripts inside iframe
allow-top-navigation: Allow navigation to top level window

Перегляньте: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-sandbox

Тепер, подумайте, що зловмисник використовував наступний код для розміщення вашого сайту в iframe:

<iframe src="URI" sandbox></iframe>

Тоді, весь код перебору кадру JavaScript буде відмовлений.

Перевіривши весь код завантаження кадру, лише ця захист працює у всіх випадках:

<style id="antiClickjack">body{display:none !important;}</style>
<script type="text/javascript">
   if (self === top) {
       var antiClickjack = document.getElementById("antiClickjack");
       antiClickjack.parentNode.removeChild(antiClickjack);
   } else {
       top.location = self.location;
   }
</script>

що спочатку запропонували Густав Райдштет, Елі Бурштейн, Ден Боне та Колін Джексон (2010)


19

Трохи задумавшись над цим, я вірю, що це покаже їм, хто бос ...

if(top != self) {
  window.open(location.href, '_top');
}

Використовуючи _topяк цільовий параметр для window.open(), запустіть його в тому ж вікні.


6
if (top != self) {
  top.location.replace(location);
  location.replace("about:blank"); // want me framed? no way!
}

6

Я збираюся бути сміливим і кидаю капелюх на ринг на цьому (давній, як це є), подивіться, скільки лісів я можу зібрати.

Ось моя спроба, яка, здається, працює всюди, де я її перевірив (Chrome20, IE8 і FF14):

(function() {
    if (top == self) {
        return;
    }

    setInterval(function() {
        top.location.replace(document.location);
        setTimeout(function() {
            var xhr = new XMLHttpRequest();
            xhr.open(
                'get',
                'http://mysite.tld/page-that-takes-a-while-to-load',
                false
            );
            xhr.send(null);
        }, 0);
    }, 1);
}());

Я помістив цей код у <head>і назвав його з кінця сторінки, <body>щоб переконатися, що моя сторінка виведена до того, як вона почне сперечатися зі шкідливим кодом, не знаю, чи це найкращий підхід, YMMV.

Як це працює?

... Я чую, що ви запитуєте - ну чесна відповідь, я насправді не знаю. Потрібно було багато хитрощів, щоб змусити його працювати скрізь, де я тестував, і точний ефект, який він має, незначно змінюється залежно від місця його запуску.

Ось мислення за цим:

  • Встановіть функцію, щоб вона працювала на мінімально можливому інтервалі. Основна концепція будь-якого з реалістичних рішень, які я бачив, - це заповнити планувальник більшістю подій, ніж має кадр-бустер.
  • Кожен раз, коли функція спрацьовує, спробуйте змінити розташування верхнього кадру. Досить очевидна вимога.
  • Також заплануйте негайно запустити функцію, яка потребуватиме тривалого часу (тим самим блокуючи перемикач кадрів від перешкод для зміни місця розташування). Я вибрав синхронний XMLHttpRequest, тому що це єдиний механізм, про який я думаю, що не вимагає (або принаймні запитувати) взаємодії з користувачем і не розжовує час процесора користувача.

Для моєї http://mysite.tld/page-that-takes-a-while-to-load(цілі XHR) я використав сценарій PHP, який виглядає приблизно так:

<?php sleep(5);

Що сталося?

  • Chrome і Firefox чекають 5 секунд, поки завершиться XHR, після чого успішно переспрямуйте на URL-адресу оформленої сторінки.
  • IE майже відразу переадресовує

Ви не можете уникнути часу очікування в Chrome і Firefox?

Мабуть, ні. Спочатку я вказав XHR на URL, який повертав би 404 - це не працювало у Firefox. Тоді я спробував sleep(5);підхід, який я врешті-решт приземлився для цієї відповіді, потім я різними способами почав грати довкола сну. Я не міг знайти реальну схему поведінки, але я виявив, що якщо вона занадто коротка, конкретно Firefox не буде грати в м'яч (Chrome і IE, схоже, ведуть себе досить добре). Я не знаю, що таке поняття "занадто коротке" в реальному вираженні, але 5 секунд, здається, працює кожен раз.


Якщо будь-які перехожі ніндзя Javascript хочуть трохи краще пояснити, що відбувається, чому це (ймовірно) неправильно, ненадійно, найгірший код, який вони коли-небудь бачили тощо. Я з радістю слухаю.


Здається, ви можете видалити всі свої тривожні пропозиції
mplungjan

6

З 2015 року для цього слід використовувати frame-ancestorsдирективу CSP2 . Це реалізується через заголовок відповіді HTTP.

напр

Content-Security-Policy: frame-ancestors 'none'

Звичайно, не дуже багато браузерів підтримують CSP2, але розумно включити старий X-Frame-Optionsзаголовок:

X-Frame-Options: DENY

Я б радив включати обидва в будь-якому випадку, інакше ваш сайт буде залишатися вразливим до атак Clickjacking у старих браузерах, і, звичайно, ви отримаєте небажане обрамлення навіть без шкідливих намірів. Більшість браузерів оновлюються автоматично ці дні, однак ви все ще схильні заставляти корпоративних користувачів на старих версіях Internet Explorer із застарілих причин сумісності програм.


1
Усі основні браузери зараз підтримують CSP. Це правильна відповідь у 2019 році та осяжне майбутнє.
Stephen R

5

Гаразд, тому ми знаємо, що були в кадрі. Тож ми розміщуємо.href на іншу спеціальну сторінку з контуром як GET-змінною. Тепер ми пояснюємо користувачеві, що відбувається, і надаємо посилання з опцією target = "_ TOP". Це просто і, ймовірно, працює (ще не перевіряли його), але це вимагає певної взаємодії з користувачем. Можливо, ви могли вказати користувачу сайт, що ображає, і зробити кудись сором, якийсь десь на вашому сайті кладет хакери .. Просто ідея, але це працює ніч ..


5

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

Я написав прототип, де за замовчуванням усі входи (посилання, форми та елементи введення) відключені та / або нічого не роблять при активації.

Якщо кадр, що містить міститься, вхідні дані залишаються відключеними, а вгорі сторінки відображається попереджувальне повідомлення. Попереджувальне повідомлення містить посилання, яке відкриє безпечну версію сторінки в новому вікні. Це запобігає використанню сторінки для переключення кліків, при цьому все ж дозволяє користувачеві переглядати вміст в інших ситуаціях.

Якщо не знайдено жодного фрейму, що міститься, вхід увімкнено.

Ось код. Потрібно встановити стандартні атрибути HTML на безпечні значення та додати додаткові атрибути, що містять фактичні значення. Це, мабуть, неповно, і для повної безпеки додаткові атрибути (я маю на увазі обробників подій), ймовірно, повинні будуть трактуватися так само:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
  <head>
    <title></title>
    <script><!--
      function replaceAttributeValuesWithActualOnes( array, attributeName, actualValueAttributeName, additionalProcessor ) {
        for ( var elementIndex = 0; elementIndex < array.length; elementIndex += 1 ) {
          var element = array[ elementIndex ];
          var actualValue = element.getAttribute( actualValueAttributeName );
          if ( actualValue != null ) {
            element[ attributeName ] = actualValue;
          }

          if ( additionalProcessor != null ) {
            additionalProcessor( element );
          }
        }
      }

      function detectFraming() {
        if ( top != self ) {
          document.getElementById( "framingWarning" ).style.display = "block";
        } else {
          replaceAttributeValuesWithActualOnes( document.links, "href", "acme:href" );

          replaceAttributeValuesWithActualOnes( document.forms, "action", "acme:action", function ( form ) {
            replaceAttributeValuesWithActualOnes( form.elements, "disabled", "acme:disabled" );
          });
        }
      }
      // -->
    </script>
  </head>
  <body onload="detectFraming()">
    <div id="framingWarning" style="display: none; border-style: solid; border-width: 4px; border-color: #F00; padding: 6px; background-color: #FFF; color: #F00;">
      <div>
        <b>SECURITY WARNING</b>: Acme App is displayed inside another page.
        To make sure your data is safe this page has been disabled.<br>
        <a href="framing-detection.html" target="_blank" style="color: #090">Continue working safely in a new tab/window</a>
      </div>
    </div>
    <p>
      Content. <a href="#" acme:href="javascript:window.alert( 'Action performed' );">Do something</a>
    </p>
    <form name="acmeForm" action="#" acme:action="real-action.html">
      <p>Name: <input type="text" name="name" value="" disabled="disabled" acme:disabled=""></p>
      <p><input type="submit" name="save" value="Save" disabled="disabled" acme:disabled=""></p>
    </form>
  </body>
</html>

Проблема в цьому полягає в тому, що виробник кадрів може використовувати позицію: абсолютно розмістити активну кнопку поверх неактивних кнопок, і користувач просто побачить вашу веб-сторінку і подумає, що вони натискають ваші кнопки.
jmucchiello

Попереджувальне повідомлення все одно відображатиметься, але, звичайно, легко прикрити посилання на безпечну сторінку, як ви пропонуєте. Але навіщо переживати усі проблеми створення моєї сторінки, щоб змусити людей натискати на знайомі кнопки, якщо ви можете просто скопіювати сторінку та досягти такого ж ефекту? Код, наведений вище, головним чином запобігає відхиленню кліків. Якщо ви побачите мою сторінку непомітно вище іншої сторінки, неможливо викликати дії на моєму сайті.
Йохан Стюйц,

Якщо він розміщений в рамці з обмеженими зонами IE8 або в рамці пісочної скриньки Chrome, JavaScript ніколи не запускається. Цікаво, які модифікації потрібні в тих випадках
goodguys_activate

4

Ну, ви можете змінити значення лічильника, але це, очевидно, крихке рішення. Ви можете завантажувати свій вміст через AJAX після того, як визначите, що сайт знаходиться не в рамках - також не чудове рішення, але, сподіваємось, уникнете запуску події перед завантаженням (я припускаю).

Правка: Ще одна ідея. Якщо ви виявите, що ви знаходитесь у кадрі, попросіть користувача відключити javascript, перш ніж натиснути на посилання, яке перенаправляє вас до потрібної URL-адреси (передаючи рядок запитів, що дозволяє вашій сторінці знати, щоб сказати користувачеві, що вони можуть знову включити javascript, як тільки вони є там).

Редагувати 2: Перейти до ядерної - якщо ви виявите, що перебуваєте у кадрі, просто видаліть вміст тіла документа та надрукуйте якесь неприємне повідомлення.

Редагувати 3: Чи можна перерахувати верхній документ і встановити всі функції на нуль (навіть анонімні)?


Перспектива (раніше Hotmail) "виходить з ладу", якщо вона не може вийти з кадру - вона вміщує весь вміст <body>всередині <plaintext>тегу, встановленого на display: none. Це досить ефективно.
uınbɐɥs

4

Якщо ви додасте попередження одразу після коду маршрутизатора, то сповіщення зупинить потік javascript, і це дозволить завантажувати сторінку. Це те, що робить StackOverflow, і воно вибивається з моїх кадрів, навіть коли я використовую перемикач кадру. Це також працювало з моєю простою тестовою сторінкою. Це було протестовано лише у Firefox 3.5 та IE7 на windows.

Код:

<script type="text/javascript">
if (top != self){
  top.location.replace(self.location.href);
  alert("for security reasons bla bla bla");
}
</script>

3

Я думаю, ти майже був там. Ти намагався:

window.parent.onbeforeunload = null;
window.parent.location.replace(self.location.href);

або, альтернативно:

window.parent.prevent_bust = 0;

Примітка: я насправді цього не перевіряв.


1
Я відредагував зразок вашого коду (здається, тест для батьків не працює), але відредагована версія НЕ працює!
Джефф Етвуд

1
Класно. Завжди важко відповісти неперевіреним кодом - я роблю це, щоб принаймні зрозуміти ідею, - і нехай бідний запитувач налагоджує. :)
Jeff Meatball Ян

12
Не працює, якщо батько перебуває на іншому домені, імовірно, це так!
Джош Стодола

2

А як з тим, щоб дзвонити до цього ще раз? Це створить умову гонки, але можна сподіватися, що бастер вийде на вершину:

(function() {
    if(top !== self) {
        top.location.href = self.location.href;
        setTimeout(arguments.callee, 0);
    }
})();

2

Якщо ви подивитеся на значення, що повертаються, setInterval()вони зазвичай є одноцифровими, тож ви можете вимкнути всі такі переривання одним рядком коду:

for (var j = 0 ; j < 256 ; ++j) clearInterval(j)

2

Я, можливо, тільки що знайшов спосіб розбити javascript-роутер Buster. Використовуючи функцію getElementsByName у своїй функції javascript, я встановив цикл між накопичувачем кадрів та фактичним сценарієм запуску кадрів. перевірити цю публікацію. http://www.phcityonweb.com/frame-buster-buster-buster-2426


0

setInterval і setTimeout створюють інтервал автоматичного збільшення. Кожен раз, коли викликається setTimeout або setInterval, це число збільшується на одиницю, так що якщо ви зателефонуєте на setTimeout, ви отримаєте поточне, найвище значення.

   var currentInterval = 10000;
   currentInterval += setTimeout( gotoHREF, 100 );
   for( var i = 0; i < currentInterval; i++ ) top.clearInterval( i );
   // Include setTimeout to avoid recursive functions.
   for( i = 0; i < currentInterval; i++ )     top.clearTimeout( i );

   function gotoHREF(){
           top.location.href = "http://your.url.here";
   }

Оскільки майже не чутно, щоб було 10000 одночасних встановлених інтервалів та setTimeouts, а оскільки setTimeout повертає "останній інтервал або час очікування створено + 1", а оскільки top.clearInterval все ще доступний, це переможе атаки чорної шапки на кадр веб-сайти, описані вище.


0

Використовуйте htaccess, щоб уникнути набору кадрів із високим рівнем доступу, iframe та будь-якого вмісту, такого як зображення.

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://www\.yoursite\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule ^(.*)$ /copyrights.html [L]

Це покаже сторінку авторських прав замість очікуваної.


Це покладається на реферала, який а) не завжди встановлюється (через налаштування чи розширення веб-переглядача або просто тому, що сторінка, що переглядає, використовує HTTPS без використання <meta name="referrer" …/>та b), також встановлюється при натисканні на посилання, тому ви також забороняєте посилання на вашу сторінку та переривання Інтернет.
Мартін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.