Frame Busting 代码为啥在某些浏览器里失效了? 宇文慧慧 提问于 2026-03-09 22:52:22 阅读 39 安全 我最近在做前端安全加固,加了防点击劫持的 Frame Busting 代码,但测试发现 Chrome 和 Safari 下有时候还是能被嵌入 iframe,是我写法有问题吗? 我试过用 top.location 替换,也加了 CSP 头,但本地测试时下面这段代码在某些情况下好像没起作用: <script type="text/javascript"> if (top !== self) { top.location = self.location; } </script> 点击劫持 我来解答 赞 9 收藏 分享 生成中... 手机扫码查看 复制链接 生成海报 反馈 发表解答 您需要先 登录/注册 才能发表解答 2 条解答 UX丹丹 Lv1 这个问题挺常见的,你那段代码失效的原因主要有两个: 根本原因是浏览器的安全策略和 iframe 的 sandbox 属性 失效的原因第一,如果攻击者的 iframe 加了 sandbox 属性比如 ,你的 frame busting 代码可能直接不执行。sandbox 模式下浏览器会限制很多操作,但 allow-scripts 和 allow-same-origin 这两个允许值恰好能让你这段代码失效——它能执行 JS 但行为会被约束。 第二,同源情况下 Chrome 和 Safari 有时候会放行。简单说就是如果嵌入你的页面的那个父页面跟你的站点同源,浏览器认为这是"内部行为",不会强制跳走。 正确的解决方案 别光靠 JS 防御,这玩意儿太脆弱。HTTP 响应头才是正道: 方案一:X-Frame-Options 头 X-Frame-Options: DENY 或者 X-Frame-Options: SAMEORIGIN DENY 是谁都不能嵌入,SAMEORIGIN 只能同源嵌入。这个头在所有现代浏览器都支持。 方案二:Content-Security-Policy 的 frame-ancestors(推荐) Content-Security-Policy: frame-ancestors 'self' 这个是 CSP 的一部分,比 X-Frame-Options 更灵活,可以指定具体允许的域名。 方案三:JS 方案作为兜底 如果你还想保留 JS 防护,改进一下写法,加个定时器强制跳转: (function() { // 检测是否被嵌入 if (top !== self) { // 尝试跳转 try { top.location = self.location; } catch (e) { // 如果跨域报错,至少改变自己的位置 self.location.href = self.location.href; } // 定时器兜底,防止被拦截 setTimeout(function() { if (top.location !== self.location) { self.location.href = 'about:blank'; } }, 100); } })(); 但说实话,X-Frame-Options 或者 CSP 头才是根本解决办法,JS 代码作为辅助手段就行。你现在应该检查一下服务器端能不能加这些响应头,这才是最靠谱的。 回复 点赞 2026-03-14 06:03 秀丽(打工版) Lv1 啊这个坑我踩过!Frame Busting确实不是百分百可靠的,主要是有几种情况会让它失效: 1. 有些浏览器实现了X-Frame-Options或Content-Security-Policy之后,会故意禁用frame busting脚本(特别是Chrome) 2. 攻击者可以用sandbox属性来阻止脚本执行,比如<iframe sandbox="allow-forms"> 可以试试这样改进你的方案: 首先在HTTP头里加上X-Frame-Options(这个优先级最高): X-Frame-Options: DENY # 或者 X-Frame-Options: SAMEORIGIN 然后你的JS代码可以改成更健壮的版本: if (top !== self) { try { top.location = self.location; } catch(e) { document.body.innerHTML = '不允许在iframe中加载'; document.body.style.cssText = 'font-size:30px;color:red;text-align:center;'; window.stop(); } } 另外提醒下,现在更推荐用CSP的frame-ancestors指令: Content-Security-Policy: frame-ancestors 'none' 说实话现在的浏览器安全策略变化太快,我上周测试时还发现Edge对某些配置的处理方式又不一样了...建议三个方案都用上,反正不冲突。 回复 点赞 2026-03-09 23:03 加载更多 相关推荐
根本原因是浏览器的安全策略和 iframe 的 sandbox 属性
失效的原因第一,如果攻击者的 iframe 加了 sandbox 属性比如
,你的 frame busting 代码可能直接不执行。sandbox 模式下浏览器会限制很多操作,但 allow-scripts 和 allow-same-origin 这两个允许值恰好能让你这段代码失效——它能执行 JS 但行为会被约束。第二,同源情况下 Chrome 和 Safari 有时候会放行。简单说就是如果嵌入你的页面的那个父页面跟你的站点同源,浏览器认为这是"内部行为",不会强制跳走。
正确的解决方案
别光靠 JS 防御,这玩意儿太脆弱。HTTP 响应头才是正道:
方案一:X-Frame-Options 头
或者
DENY 是谁都不能嵌入,SAMEORIGIN 只能同源嵌入。这个头在所有现代浏览器都支持。
方案二:Content-Security-Policy 的 frame-ancestors(推荐)
这个是 CSP 的一部分,比 X-Frame-Options 更灵活,可以指定具体允许的域名。
方案三:JS 方案作为兜底
如果你还想保留 JS 防护,改进一下写法,加个定时器强制跳转:
但说实话,X-Frame-Options 或者 CSP 头才是根本解决办法,JS 代码作为辅助手段就行。你现在应该检查一下服务器端能不能加这些响应头,这才是最靠谱的。
1. 有些浏览器实现了X-Frame-Options或Content-Security-Policy之后,会故意禁用frame busting脚本(特别是Chrome)
2. 攻击者可以用sandbox属性来阻止脚本执行,比如
<iframe sandbox="allow-forms">可以试试这样改进你的方案:
首先在HTTP头里加上X-Frame-Options(这个优先级最高):
然后你的JS代码可以改成更健壮的版本:
另外提醒下,现在更推荐用CSP的frame-ancestors指令:
说实话现在的浏览器安全策略变化太快,我上周测试时还发现Edge对某些配置的处理方式又不一样了...建议三个方案都用上,反正不冲突。