JavaScript检测无法防御点击劫持,因攻击者可通过sandbox禁用脚本、srcdoc/data:协议绕过或服务端渲染跳过执行;真正有效的是服务端设置X-Frame-Options或CSP frame-ancestors响应头,浏览器在解析前强制拦截。

直接在响应头里加 X-Frame-Options 或 Content-Security-Policy,这是最可靠、浏览器强制执行的方式;仅靠前端 JS 检测 window.top !== window.self 是无效的防御。
为什么不能只靠 JavaScript 判断是否被嵌套
很多开发者会写类似这样的代码:
if (window.top !== window.self) {
document.body.innerHTML = '';
}
这看起来能“阻止”被 iframe 嵌入,但实际毫无防护力:
- 恶意站点完全可以在 iframe 加载你的页面前,就用
sandbox属性禁掉脚本执行,让这段 JS 根本不运行 - 即使 JS 执行了,它只能清空自己页面的内容,而父页仍可截图、录屏、监听网络请求或通过
iframe.contentDocument(同源时)读取 DOM - 攻击者还可绕过 JS 检查:比如用
srcdoc内联 HTML、用data:协议加载、或利用服务端渲染跳过客户端逻辑
X-Frame-Options 响应头怎么配才生效
X-Frame-Options 是 HTTP 响应头,由服务器返回,浏览器在解析 HTML 前就决定是否渲染该页面到 iframe 中。它只有三个合法值:
立即学习“前端免费学习笔记(深入)”;
-
DENY:任何页面都不能用 iframe 嵌入本页(最严格) -
SAMEORIGIN:只允许同域下的 iframe 嵌入(适合内部子应用间嵌套) -
ALLOW-FROM https://trusted.example.com:仅允许指定来源嵌入(注意:Chrome 和 Firefox 已弃用此值,仅 Safari 部分支持)
关键点:
- 必须由后端设置,前端无法用
meta标签模拟(<meta http-equiv="X-Frame-Options">被所有现代浏览器忽略) - 如果同时设置了
X-Frame-Options和Content-Security-Policy的frame-ancestors,后者优先级更高 - Apache 示例:
Header always set X-Frame-Options "DENY";Nginx:add_header X-Frame-Options "DENY" always;
Content-Security-Policy 的 frame-ancestors 更推荐
相比 X-Frame-Options,Content-Security-Policy 的 frame-ancestors 指令更灵活、更现代,且已被所有主流浏览器支持(截至 2026 年):
-
frame-ancestors 'none'≡X-Frame-Options: DENY -
frame-ancestors 'self'≡X-Frame-Options: SAMEORIGIN -
frame-ancestors https://a.com https://b.net:允许多个明确域名(支持 HTTPS 协议限定)
注意:
- 必须使用单引号包裹关键字(如
'none'),双引号或不加引号会失效 - 不能和
X-Frame-Options混用——若两者冲突,frame-ancestors生效,但旧版 IE(已基本淘汰)只认X-Frame-Options - 响应头写法:
Content-Security-Policy: frame-ancestors 'none';
iframe sandbox 属性对本站没用,别白费力气
有人试图在自己页面的 <iframe> 标签上加 sandbox 来“防被嵌”,这是方向性错误:
-
sandbox是用来限制「当前 iframe 内加载的内容」的行为(比如禁止脚本、表单提交),不是用来保护「当前页面不被别人嵌」 - 你在自己的 HTML 里写
<iframe sandbox src="...">,只影响那个 iframe 里的子页面,跟你是否被别人嵌入完全无关 - 真正要防的是别人把你页面当
src放进他们的 iframe —— 这件事你控制不了 DOM 结构,只能靠响应头拦截
真正起作用的,永远是服务端返回的响应头;其他一切前端手段,都是障眼法。



















