x-frame-options仅deny和sameorigin有效,allow-from已被主流浏览器弃用;nginx配置需加always参数并覆盖所有location;反向代理层统一配置最稳妥;须验证所有状态码路径是否生效。

直接加 X-Frame-Options 响应头就能防点击劫持,但必须选对值、放对位置,否则可能被绕过或导致自身功能异常。
为什么 DENY 和 SAMEORIGIN 是唯二可用选项
ALLOW-FROM 已被 Chrome 79+、Firefox 69+ 等主流浏览器彻底弃用,配置了也无效。实际只剩两个可靠选择:
-
DENY:页面完全不允许被任何<iframe></iframe>嵌入,适合管理后台、支付页等敏感入口 -
SAMEORIGIN:只允许同协议+域名+端口的页面嵌入,适合需要内部 iframe 通信的单页应用(如仪表盘嵌子模块)
别写 ALLOW-FROM https://trusted.example.com —— 浏览器会忽略它,还可能让你误以为防护生效。
Nginx 中 add_header 必须加 always 参数
默认情况下,add_header 只在 2xx 响应中生效,而 301/302 跳转、404 页面都不会带这个头,攻击者正好可以利用这些路径绕过防护。
正确写法是:
add_header X-Frame-Options "DENY" always;
漏掉 always 就等于在错误码页面留了个 iframe 入口。
另外,不要只在 server 块里配,如果用了多个 location 规则(比如静态资源走单独路径),得确保每个 relevant location 都覆盖到,或者统一放在 http 块顶层。
Serve、Spring Boot、Tomcat 的配置差异点
不同服务层添加头的方式看似一样,但生效逻辑和优先级不同:
-
serve命令行加--header "X-Frame-Options: SAMEORIGIN"仅对当前启动实例有效,重启即失效 - Spring Boot 中若用
HttpSecurity.headers().frameOptions().deny(),会覆盖所有路径,但若同时启用了 CSP,frame-ancestors优先级更高,两者冲突时以 CSP 为准 - Tomcat 的
web.xml中配置<filter></filter>添加头,要注意 filter 链顺序 —— 如果有其他安全 filter(如 CORS)在前且提前返回,X-Frame-Options可能根本没机会写入响应
最稳妥的做法:在反向代理层(如 Nginx)统一加,而不是依赖应用层,避免因框架升级或配置遗漏导致漏配。
验证时别只看首页,要测所有状态码路径
开发者工具里只查 / 的响应头是不够的。攻击者常利用 404、500、/favicon.ico 等非主页面路径嵌入 iframe —— 这些路径往往被忽略。
验证步骤:
- 用 curl 检查关键路径:
curl -I https://yoursite.com/404、curl -I https://yoursite.com/login - 打开开发者工具 → Network → 切换到任意一个 4xx/5xx 请求 → 查看 Response Headers 是否含
X-Frame-Options - 手动建一个测试 HTML,用
<iframe src="https://yoursite.com/xxx"></iframe>实际加载,看是否被拒绝
很多团队配了头却没发现 404 页面没生效,结果攻击者用错误页做跳板,防护形同虚设。











