Nginx 安全响应头配置:用几行配置挡住常见攻击
点击劫持、MIME 类型嗅探、隐私泄露……这些问题很多都能靠 HTTP 响应头缓解。Nginx 里加几行 add_header,就能显著缩小前端攻击面,成本几乎为零。本文给出可直接使用的配置,并解释每个头的用途和取舍。安全响应头不解决所有问题,但它们是成本最低、收益最稳的一层防线,适合任何规模的站点先做起来。
这些头能挡住什么
X-Frame-Options 直接禁止页面被第三方 iframe 加载,是点击劫持的头号防线;X-Content-Type-Options: nosniff 让浏览器老老实实按 Content-Type 解析,能减少一部分 XSS 变体;Referrer-Policy 控制外链跳转时泄露多少来源信息,strict-origin-when-cross-origin 在多数场景下既能保留站内分析所需的信息,又不至于把完整 URL 带出去;Permissions-Policy 则把定位、摄像头、麦克风这类高敏感权限默认关掉,第三方脚本即使被注入也没法悄悄调用。
配置示例
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=()" always;
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data: https:;" always;
参考:OWASP Secure Headers Project https://owasp.org/www-project-secure-headers/
每个头在干什么
| 响应头 | 作用 | 建议值 |
|---|---|---|
| X-Frame-Options | 防止站点被嵌入 iframe 点击劫持 | SAMEORIGIN 或 DENY |
| X-Content-Type-Options | 禁止浏览器猜测 MIME 类型 | nosniff |
| Referrer-Policy | 控制跳转时携带的 Referrer 信息 | strict-origin-when-cross-origin |
| Permissions-Policy | 限制浏览器 API 权限(定位、摄像头等) | 按需禁用 |
| Content-Security-Policy | 白名单式控制资源加载来源 | 按站点实际情况配置 |
一个真实场景:活动页被套进广告 iframe
某站点上线了一个砍价活动页,几天后收到用户反馈"页面被包在广告里点不动"。排查发现是第三方脚本把活动页放进了自己的 iframe,通过透明遮罩诱导点击——典型的点击劫持。加上 X-Frame-Options: DENY 后,页面拒绝被任何 iframe 加载,问题立即消失。这件事也给团队提了个醒:凡是涉及用户点击的页面,都应该默认拒绝被嵌入,除非业务确实需要 iframe 分享。
CSP 是重点也是难点
Content-Security-Policy 是目前最强大的响应头,但也最容易误伤。把 default-src 'self' 直接上线,第三方统计、广告、字体脚本可能全部被拦。推荐的落地路径:
- 先开 Report-Only 模式,只上报不拦截,观察一周:
Content-Security-Policy-Report-Only。 - 收集违规报告,把第三方域名逐个加进白名单。
- 确认无误后再切换到强制模式,并保留上报接口用于持续监控。
这也是安全响应头指南里强调的"先试运行再强制"原则。CSP 落地示例:统计脚本域名加到 script-src,字体域名加到 font-src,图片 CDN 加到 img-src,逐项收敛。
用 curl 验证
curl -sI https://example.com | grep -iE 'x-frame|x-content|content-security|referrer'
返回结果里能看到对应的响应头即生效。也可以借助在线检查工具(如 SecurityHeaders.com)给站点打分,逐项补齐。
常见问题
加了这些头会影响 SEO 吗? 不会,搜索引擎对标准安全响应头没有负面评价;相反,它们还能减少站点被恶意站点伪装的风险。CSP 会把我的广告和统计脚本拦掉吗? 会,如果没把对应域名加进白名单。这就是为什么先开 Report-Only 模式观察,再逐步放开。每个站都要配一遍吗? 可以把公共配置放到 conf.d/security-headers.conf 再 include,全站统一生效;个别需要放开的站点单独覆盖即可。可以用哪些工具自检? 除了 curl,还有 SecurityHeaders.com、Mozilla Observatory、Chrome DevTools 的响应头面板,跑一遍就能看到缺失项。为什么 curl 看到的头和浏览器不一样? 浏览器会执行 CSP 报告、cookie 处理等逻辑,curl 只拿原始响应,两者行为不同是正常的。
与 CDN 和反向代理配合
站点前面有 CDN 或反向代理时,安全头也可以在最外层加:CDN 缓存页面的同时会缓存响应头,所以头配置尽量在 CDN 控制台或边缘节点统一设置,避免每台源站各配一套。Nginx 反代场景下,proxy_hide_header 可以过滤源站回传的多余头,add_header 在代理层追加安全头。注意顺序:源站、反代、CDN 三层都能加头,最外层的值会覆盖或叠加,调试时用 curl 逐个确认最终响应里带了哪些。如果源站后面还套了多级代理,安全头会被逐层透传,最外层负责兜底,里层保持简洁即可。
注意事项
add_header只有在当前作用域有响应时才会输出。想确保安全头在 200/404/302 等所有响应上都出现,记得加always关键字。- 有第三方脚本(统计、支付、客服)的站点,CSP 先白名单再收紧,避免功能异常。
- 安全头属于Web 安全加固的一部分,配合WAF 配置和XSS 防护效果更好。
更完整的头部清单与配置模板,见安全响应头配置指南;整套安全方案可以参考安全加固分类。