nginx 防范点击劫持的核心是配置 x-frame-options 和 csp frame-ancestors 响应头,按路径精准设置 deny 或 sameorigin,并加 always 参数确保所有响应生效,同时避免全局误配和与 csp 冲突。

用 Nginx 防范跨站点击劫持,核心是控制页面能否被嵌入 iframe。这不是靠改前端或加 JS 实现的,而是通过 HTTP 响应头在服务器出口处直接拦截——既轻量,又可靠。
必须配 X-Frame-Options 头
这是最基础、兼容性最好的防线,所有主流浏览器都支持。它不防 XSS 或 CSRF,但专治 iframe 嵌套。
- DENY:全站禁止任何嵌入,适合登录页、支付页、后台管理入口
- SAMEORIGIN:只允许同域名下的页面嵌入,适合需内部 iframe 协作的场景(如子系统集成)
- ALLOW-FROM https://trusted.example.com:指定白名单域名(注意:Chrome 早已弃用该值,不推荐)
- 务必加 always 参数,确保 304、204、错误页等所有响应都带上该头
按路径精准配置,别全局乱加
很多故障源于把 add_header X-Frame-Options 写在 server 块顶层——结果 JSON 接口、JS/CSS 文件、健康检查地址也带上了这个头,语义错误还可能触发扫描告警。
- 只对 HTML 页面生效才有意义,所以应放在 PHP 执行路径里:
location ~ \.php$ { ... } - 静态资源(
location ~* \.(js|css|png|jpg)$)不用设,也不该设 - API 接口(如
/api/、/healthz)建议显式排除,避免干扰
搭配 CSP 的 frame-ancestors 更稳妥
X-Frame-Options 是“老将”,CSP 的 frame-ancestors 是“新锐”。两者共存不冲突,还能互补:
- CSP 更灵活,支持
'none'、'self'、'https://a.com'等细粒度策略 - 现代浏览器优先执行
frame-ancestors,忽略X-Frame-Options;老浏览器则依赖后者兜底 - 配置示例:
add_header Content-Security-Policy "frame-ancestors 'self';" always;
上线前必须验证是否生效
配完不验证 = 白配。重点看三点:
- 打开 Chrome DevTools → Network → 刷一次页面 → 找 HTML 请求 → 检查 Response Headers 是否含
X-Frame-Options: DENY(或对应值) - 用 curl 测试:
curl -I https://yoursite.com/login,确认头存在且值正确 - 手动建一个含 iframe 的测试页,尝试嵌入你的目标 URL,观察是否被浏览器拒绝渲染











