假设你不希望其他网站在<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>
这段代码执行以下操作:
每次浏览器试图通过窗口导航离开当前页面时,递增一个计数器。Onbeforeunload事件处理程序
设置一个计时器,通过setInterval()每毫秒触发一次,如果它看到计数器增加,则将当前位置更改为攻击者控制的服务器
该服务器提供一个HTTP状态码为204的页面,这不会导致浏览器在任何地方导航
我的问题是——这更像是一个JavaScript难题,而不是一个实际问题——如何打败框架破坏破坏者?
我有一些想法,但在我的测试中没有什么管用:
试图通过onbeforeunload = null清除onbeforeunload事件没有效果
添加alert()会停止进程,让用户知道它正在发生,但不会以任何方式干扰代码;单击OK,让破坏照常进行
我想不出任何方法来清除setInterval()定时器
我不是一个很好的JavaScript程序员,所以这是我对你的挑战:嘿,老兄,你能打破框架破坏老兄吗?
我将勇敢地把我的帽子投到这个戒指上(尽管它很古老),看看我能收集到多少反对票。
以下是我的尝试,在我测试的所有地方(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。
它是如何工作的?
...我听到你问了——诚实的回答是,我真的不知道。为了让它在我测试的所有地方都能正常工作,我花了很多功夫,而且它的确切效果会因运行位置的不同而略有不同。
这背后的想法是:
Set a function to run at the lowest possible interval. The basic concept behind any of the realistic solutions I have seen is to fill up the scheduler with more events than the frame buster-buster has.
Every time the function fires, try and change the location of the top frame. Fairly obvious requirement.
Also schedule a function to run immediately which will take a long time to complete (thereby blocking the frame buster-buster from interfering with the location change). I chose a synchronous XMLHttpRequest because it's the only mechanism I can think of that doesn't require (or at least ask for) user interaction and doesn't chew up the user's CPU time.
对于我的http://mysite.tld/page-that-takes-a-while-to-load (XHR的目标),我使用了一个PHP脚本,看起来像这样:
<?php sleep(5);
会发生什么呢?
Chrome和Firefox在XHR完成时等待5秒,然后成功重定向到框架页面的URL。
IE几乎立即重定向
你不能避免在Chrome和Firefox中等待时间吗?
Apparently not. At first I pointed the XHR to a URL that would return a 404 - this didn't work in Firefox. Then I tried the sleep(5); approach that I eventually landed on for this answer, then I started playing around with the sleep length in various ways. I could find no real pattern to the behaviour, but I did find that if it is too short, specifically Firefox will not play ball (Chrome and IE seem to be fairly well behaved). I don't know what the definition of "too short" is in real terms, but 5 seconds seems to work every time.
如果任何路过的Javascript高手想要更好地解释一下发生了什么,为什么这(可能)是错误的,不可靠的,为什么这是他们见过的最糟糕的代码等等,我很乐意听。
考虑到当前的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>
最初由Gustav Rydstedt, Elie Bursztein, Dan Boneh和Collin Jackson提出(2010)