X-Frame-Options 无法彻底杜绝点击劫持,需与 CSP frame-ancestors 共存、分路径精准配置并主动验证。它仅控制 iframe 嵌入,不防 XSS/CSRF,合法值为 DENY、SAMEORIGIN(推荐)或已废弃的 ALLOW-FROM。

单靠 Nginx 配置 X-Frame-Options 无法“彻底杜绝”点击劫持,但它是防御链条中关键且必须落地的一环。真正有效的防护需要语义化配置 + 多层兼容 + 主动验证,而不是加一行头就完事。
明确 X-Frame-Options 的作用边界
这个响应头只控制浏览器是否允许当前页面被嵌入 <iframe></iframe>、<frame> 或 <object></object> 中,不防 XSS、不拦 CSRF、也不替代权限校验。它只是第一道视觉隔离屏障。
合法值只有三个:
- DENY:任何场景都不允许嵌入(含同站)
- SAMEORIGIN:仅允许同源页面嵌入(推荐大多数管理页、登录页)
- ALLOW-FROM https://xxx.com:已被 Chrome/Firefox 废弃,生产环境禁用
在 Nginx 中精准配置,避免“全站一刀切”
不能写在 http 或 server 块顶层——那样会让图片、JS、CSS 等静态资源也带上该头,既无效又可能触发扫描误报。
正确做法是按响应类型分层控制:
- PHP 动态页面(如
/login、/admin/):在location ~ \.php$块内配置 - 纯 HTML 入口页(如
/index.html):在location /或具体路径块中设置 - API 接口、健康检查页(返回 JSON/TEXT):不配 X-Frame-Options,它们本就不该被 iframe 加载
示例(phpEnv 或通用 Nginx):
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
# 必须加 always,否则 302/301 重定向不生效
add_header X-Frame-Options "SAMEORIGIN" always;
}必须与 CSP 的 frame-ancestors 共存
现代浏览器(Chrome 40+、Firefox 45+、Edge 79+)优先识别 Content-Security-Policy: frame-ancestors,并直接忽略 X-Frame-Options。而 IE ≤10 只认后者。所以二者要同时配置,不可互斥。
推荐 CSP 写法(比 ALLOW-FROM 更安全灵活):
add_header Content-Security-Policy "frame-ancestors 'self';" always;
若需允许特定第三方嵌入(如 SaaS widget),可写:
add_header Content-Security-Policy "frame-ancestors 'self' https://widget.example.com;" always;
此时 X-Frame-Options 必须移除,否则二者冲突,浏览器行为不可控。
上线前必须做的三件事
配置完不等于生效,很多漏洞就卡在这一步:
- 用
curl -I http://yoursite.com/login.php直接看响应头,绕过浏览器缓存干扰 - 建一个测试页,含
<iframe src="http://yoursite.com/login.php"></iframe>,分别在同域和跨域页面中加载,观察是否被拦截 - 检查 Nginx 配置是否被覆盖:搜索整个 conf 文件,确认没有其他
add_header X-Frame-Options出现在同一 location 块中(Nginx 后写的会覆盖前写的)


















