框架克星克星…需要克星码


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
马特(Matt),上面发布的框架破坏者代码绝对有效。A ..呃..我的一个朋友..告诉我..有关此事。或者其他的东西。:)
杰夫·阿特伍德

10
杰夫,您是否正在同一域中的两个Windows上进行测试?它看起来像你,因为如果你不那么安全限制会阻止您修改“onBeforeUnload”
詹姆斯

29
附带说明:发布示例时,请使用example.orgRFC 2606中指定的域ietf.org/rfc/rfc2606.txt
Christoph

3

Answers:


149

我不确定这是否可行-但如果您无法打破框架,为什么不显示警告。例如,如果您的页面不是“首页”,则创建一个setInterval方法来尝试破坏框架。如果经过3或4次尝试后,您的页面仍不是首页,请创建一个div元素,该元素会覆盖整个页面(模式框),并带有一条消息和一个链接,例如...

您正在未经授权的框架窗口中查看此页面-(等等)潜在的安全问题)

点击此链接可解决此问题

不是最好的,但是我看不出他们可以用哪种方式来摆脱困境。


2
我已经尝试过了,这有效。我喜欢该解决方案的另一部分是,它可以使用户了解他/她在访问您的内容之前所处的网站类型。示例代码:if(parent.frames.length> 0){top.location.replace(document.location); setTimeout(function(){if(parent.frames.length> 0){document.location =“ google.com ”;}},10); }
教皇2009年

这不仅是避免滥用的一种好方法,而且对于那些可能希望对您的网站进行内嵌只是为了窥视它(尽管不允许使用)的站点而言,它非常友好。理想情况下,我认为应该使用网站首页的屏幕截图,并说明为什么不能在顶部的iframe中使用它。
wheresrhys

33
这就是Facebook的工作方式。
shamittomar 2011年

2
但是,如果破坏站点反过来会创建一个虚假的反反反...(不知道我们目前有多少反反),lighbox div本身会提供网络钓鱼链接或其他内容,那么这可能会被利用... tbc
yunzen

7
另一个想法是只用类似的东西完全擦掉页面document.write("");(在您确定要陷害之后
gabeio 2012年

211

6
极好,毫无疑问,在浏览器.exe中支持此功能是可行的。当您说“大多数浏览器”时,具体是哪个?除了IE8之外,我找不到任何有用的资源。
杰夫·阿特伍德

2
这是一个测试页:Enhanceie.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/…),自2009年初以来,使用NoScript进行的任何Firefox安装都具有该功能(hackademix.net/2009/01/29/x-frame- options-in-firefox
ssokolow 2010年

4
最好将其与javascript framebuster结合使用。
杰西·维格

1
或将其与此页面上12年12月的答案结合起来:stackoverflow.com/a/13708510/328397
goodguys_activate 2013年

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-Options答案的旁边,但是最好将两者结合使用)
Jesse Weigert

1
应该选择这个答案或我的答案:)

我喜欢您同时使用此和X-Frame-Options:deny答案的想法。
Max West

这需要JS,恕我直言,这是一个很大的负担。
纳文

1
+1-当无法使用X-FRAME-OPTIONS时,这是最佳答案。(例如,当您需要根据引荐人有条件地允许或拒绝时。)
Jay Sullivan

29

想到了这一点,它似乎至少在Firefox和Opera浏览器中有效。

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

2
Jani和Jeff的解决方案(一次编辑)都是正确的,并且等效地工作;让Jani接受,因为他的解决方案无需任何编辑即可正常工作
Jeff Atwood 2009年

29
仅当两个窗口属于同一域时,此方法才有效。当您想从框架中逃脱时,这种情况很少发生。
詹姆斯

如果涉及嵌套框架,则必须遍历框架链并删除所有onbeforeunload处理程序,而不仅仅是顶部的处理程序!
Christoph

12
重要的说明:这对我有用,因为iframe src =是动态设置的,因此跨域策略未生效。JP是完全正确的,在静态src =中这是行不通的。
Jeff Atwood,2009年

5
好吧,现在有人可以拿出相框吗?
Epaga

23

考虑到当前为iframe引入沙箱的HTML5标准,当攻击者使用沙箱时,可以禁用此页面中提供的所有框架无效代码,因为它限制了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-if​​rame-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>

最初由Gustav Rydstedt,Elie Bursztein,Dan Boneh和Collin Jackson提出(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,因为它是我能想到的唯一一种不需要(或至少要求)用户交互并且不会占用用户CPU时间的机制。

对于我http://mysite.tld/page-that-takes-a-while-to-load(XHR的目标),我使用了一个如下所示的PHP脚本:

<?php sleep(5);

怎么了?

  • XHR完成时,Chrome和Firefox等待5秒钟,然后成功重定向到框架页面的URL。
  • IE几乎立即重定向

您无法避免在Chrome和Firefox中等待时间吗?

显然不是。最初,我将XHR指向可以返回404的URL-在Firefox中不起作用。然后,我尝试了sleep(5);最终找到答案的方法,然后我开始以各种方式来研究睡眠时间。我没有发现这种行为的真实模式,但是我确实发现,如果它太短,特别是Firefox将无法发挥作用(Chrome和IE表现得相当不错)。我不知道“太短”的实际含义是什么,但是每次都用5秒可行的。


如果有任何过去的Java语言忍者想要更好地解释发生了什么,为什么这是(可能)错误,不可靠,他们见过的最糟糕的代码,等等,我会很高兴地听。


似乎您可以删除所有令人担忧的句子
mplungjan

6

从2015年开始,您应该使用CSP2的frame-ancestors指令。这是通过HTTP响应标头实现的。

例如

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

当然,还没有多少浏览器支持CSP2,因此最好包含旧的X-Frame-Options标头:

X-Frame-Options: DENY

无论如何,我都建议将两者都包括在内,否则您的网站将继续容易受到旧浏览器中的Clickjacking攻击的侵害,当然,即使没有恶意,您也将获得不受欢迎的框架。如今,大多数浏览器的确会自动更新,但是由于遗留应用程序兼容性的原因,您仍然倾向于使企业用户停留在Internet Explorer的旧版本上。


1
现在,所有主要的浏览器都支持CSP。这是2019年和可预见的未来的正确答案。
斯蒂芬·R

5

好的,所以我们知道那是在框架中。因此,我们将location.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>

问题在于框架制造商可以使用position:absolute将活动按钮放置在您的非活动按钮之上,而用户只会看到您的网页,并认为他们正在单击您的按钮。
jmucchiello

该警告消息仍将显示,但是当然很容易按照您的建议覆盖指向安全页面的链接。但是,如果您可以简单地复制页面并达到相同的效果,为什么还要麻烦整个页面来使人们单击一个熟悉的按钮呢?上面的代码主要是防止点击劫持。如果您在其他页面上方看不见显示我的页面,则无法在我的网站上调用操作。
Johan Stuyts,2009年

如果将其放置在IE8受限区域框架或Chrome沙盒框架中,则Javascript将永远不会运行。我想知道在这些情况下需要进行哪些修改
goodguys_activate 2013年

4

好了,您可以修改计数器的值,但这显然是一个脆弱的解决方案。确定站点不在框架内后,您可以通过AJAX加载内容-这也不是一个很好的解决方案,但是希望避免触发on beforeunload事件(我假设是)。

编辑:另一个想法。如果您发现自己在框架中,请先要求用户禁用javascript,然后再单击将您带到所需URL的链接(传递一个查询字符串,该字符串使您的页面知道告诉用户他们可以重新启用javascript在那里)。

编辑2:去核-如果检测到您在框架中,只需删除文档正文内容并打印一些令人讨厌的消息。

编辑3:您可以枚举顶级文档并将所有功能设置为null(甚至是匿名功能)吗?


如果Outlook(以前称为Hotmail)无法脱离框架,则会“变成核子”-将标签的全部内容<body>放入内。非常有效。<plaintext>display: none
uınbɐɥs

4

如果您在无效代码之后添加警报,那么警报将使javascript线程停滞,并让页面加载。这就是StackOverflow所做的,即使我使用帧破坏克星,它也会从我的iframe中消失。它也适用于我的简单测试页面。仅在Windows的Firefox 3.5和IE7中对此进行了测试。

码:

<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
凉。回答未经测试的代码总是很棘手-我这样做至少是为了使想法更有意义-并让可怜的asker调试。:)
杰夫·肉丸杨

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)


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个setIntervals和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]

这将显示版权页面,而不是预期的页面。


这依赖于引荐来源网址,该引荐来源网址是a)并非始终设置(由于浏览器设置或扩展功能,或者仅仅是因为引荐页面使用HTTPS而未使用<meta name="referrer" …/>b)并且在点击链接时也已设置,因此您也不允许链接到页面并中断网络。
马丁
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.