X-Frame-Options通过服务端响应头阻止iframe嵌套:DENY最安全,禁止任何嵌套;SAMEORIGIN仅允同源嵌套;ALLOW-FROM已废弃。Nginx用add_header X-Frame-Options "DENY" always; Apache及Django等框架均有对应配置,且必须由服务端发送,HTML meta无效。

怎么用 X-Frame-Options 阻止页面被 iframe 嵌套
绝大多数点击劫持攻击依赖把你的页面嵌进恶意站点的 里,再用透明层诱导用户点击。最直接有效的防护,就是让浏览器拒绝在 iframe 中加载你的页面。
关键不是前端写 JS 检测 parent,而是服务端发响应头:X-Frame-Options。它有三个值:
-
DENY:任何页面都不允许嵌套本页(最安全,推荐默认用) -
SAMEORIGIN:只允许同源页面嵌套(适合内部管理后台需 iframe 通信的场景) -
ALLOW-FROM https://trusted.example.com:仅允许指定来源(已不被 Chrome/Firefox 支持,别用)
如果你用 Nginx,加这一行就行:
add_header X-Frame-Options "DENY" always;
Apache 或后端框架(如 Express、Django)也都有对应中间件或配置项。注意:该 header 必须由服务端发出,HTML 的 标签无效。
Content-Security-Policy 的 frame-ancestors 比 X-Frame-Options 更可靠
X-Frame-Options 是老标准,已被现代浏览器逐步降级支持;而 Content-Security-Policy 中的 frame-ancestors 是它的替代方案,优先级更高,且支持更细粒度控制。
例如,禁止所有嵌套:
Content-Security-Policy: frame-ancestors 'none';
只允许同源:
Content-Security-Policy: frame-ancestors 'self';
允许多个可信域名:
Content-Security-Policy: frame-ancestors 'self' https://admin.example.com;
注意:'none' 和 'self' 必须加单引号,这是 CSP 语法要求;如果同时设置了 X-Frame-Options 和 frame-ancestors,后者会生效,前者被忽略。
前端 JS 检测 top.location 是否被劫持已基本失效
过去常见写法:if (window.top !== window.self) { window.top.location = window.self.location; },试图“跳出” iframe。这在现代浏览器中问题很多:
- Chrome/Firefox 对跨域 iframe 的
window.top.location访问抛DOMException,直接报错中断脚本 - 即使能读取,重定向也会被浏览器拦截(尤其是 HTTPS 页面嵌在 HTTP iframe 中)
- 攻击者可提前覆盖
window.top或用sandbox属性禁用 JS,绕过检测
所以,不要把防御逻辑放在前端 JS 里——它既不可靠,又容易被绕过。真正的防线必须落在响应头层面。
登录页和敏感操作页必须单独加固
点击劫持常配合 CSRF 使用:比如诱导用户在不知情下点击“确认转账”按钮。这时候光靠 frame-ancestors 'none' 不够,还要叠加其他措施:
- 所有敏感操作接口强制校验
Referer或使用一次性CSRF token - 登录页务必设置
frame-ancestors 'none',防止被嵌入钓鱼页后窃取凭证 - 如果产品确实需要嵌入(如 SSO 登录弹窗),则必须用
postMessage+ 严格 origin 校验通信,且主站 UI 层要加视觉提示(如顶部 banner 显示“正在登录 XXX”)
最容易被忽略的是:API 接口本身不防 iframe,但调用它的前端页面如果没设 frame-ancestors,整个链路就暴露了。防护得从入口页面开始,一环扣一环。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











