做 Nginx 配置这几年,要说哪个环节最容易被忽略但又最值钱,安全头绝对排得上号。很多人把证书一配、反向代理一开就觉得万事大吉,结果网站上线没几天就被安全扫描工具标了一堆“低级问题”,比如点击劫持、MIME 类型嗅探、明文传输警告。这些问题看着不痛不痒,真被利用起来还是挺麻烦的。这篇文章我就把 Nginx 里最常用、最该加的十几个安全头一次讲清楚,包含配置模板、参数选择逻辑、验证方法和踩坑记录,照着抄就能用。
先说清楚安全头到底解决什么问题。HTTP 响应头是服务器和浏览器之间传递元信息的方式,安全头就是其中一类专门约束浏览器行为的指令。比如告诉浏览器“这个页面不允许被 iframe 嵌入”“只能通过 HTTPS 加载”“不要猜测文件类型”,每一句话对应一类攻击面的收缩。配置安全头不需要改业务代码,不需要动数据库,在 Nginx 层面加几行配置就能覆盖全站所有响应,这也是我强烈建议优先在 Nginx 做这件事的原因。
这篇文章适合谁看?只要你的服务是 Nginx 对外提供访问,不管是静态站点、前端单页应用还是后端 API 网关,都值得花十分钟把这些头加上。如果你是运维、后端开发或者独立开发者,看完可以直接复制配置,再根据自己业务的实际情况调整参数。
1. 为什么要在 Nginx 层面配置安全头
1.1 安全头是浏览器和服务器之间的“安全约定”
先打个比方。你把网站比作一栋办公楼,HTTP 响应头就是入口处的安保指示牌。没有这些指示牌,访客(浏览器)只能靠自己的默认习惯行事,而浏览器的默认习惯往往不够安全。比如老版本的浏览器看到一个未知类型的文件,可能会自作主张去猜测它的真实格式,这个行为就叫 MIME 嗅探,攻击者可以利用它把恶意脚本伪装成图片上传,再诱导用户打开。安全头就是给浏览器下发明确指令:“这个楼不允许翻窗进,所有包裹必须走安检机。”
安全头的本质是“客户端安全策略”,它们的执行者是浏览器而非服务器。服务器只需要在响应头里声明策略,浏览器收到后会按照策略约束自己的行为。正因如此,配置安全头有一个天然的好处:只要浏览器遵循标准,攻击面就会直接缩小,而且这种收缩对服务器性能几乎没有影响。
1.2 在 Nginx 配置相比在应用层配置有什么优势
我在实际项目中见过不少团队把安全头写在应用代码里,比如 Java 的 Filter、Node.js 的中间件。这种做法不是不行,但有几个明显的短板:
第一,覆盖面容易有漏洞。应用层一般只能管到自己返回的动态响应,如果架构里有静态文件服务、图片裁剪服务、下载服务或者独立的网关,这些路径很容易漏掉安全头。在 Nginx 层配置是一次性覆盖所有经过它的响应,包括静态资源、错误页面、重定向响应,覆盖面完整得多。
第二,应急响应速度不一样。如果某天爆出一个新的安全头需要全网加,在 Nginx 改一行配置 reload 一下就能生效,在应用层要改代码、走发布流程、多节点滚动重启,效率差了一个量级。我在一次护网行动中就是靠 Nginx 层快速加了几个头,半小时内解决了所有相关告警。
第三,性能开销几乎为零。Nginx 加响应头是纯内存操作,不涉及业务逻辑,对 QPS 的影响可以忽略不计。相比之下,应用层每次请求都要跑一段中间件逻辑,虽然通常也不重,但总归有额外开销。
当然,应用层配置也有它的价值,比如可以根据用户角色动态生成不同的 CSP 策略。但我的建议是:以 Nginx 层为默认配置,应用层只在需要精细化控制的地方做补充,不要反过来。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 最常用的几个安全头逐一拆解
2.1 Content-Security-Policy:内容安全策略
CSP 是安全头里边最复杂、也最能体现功底的一个,它的作用是限制浏览器可以加载哪些资源。以前开发者习惯用 X-Content-Security-Policy 或者 X-WebKit-CSP 这种兼容性写法,现在主流浏览器全部支持标准头 Content-Security-Policy,直接用这个就行。
CSP 的核心逻辑是“白名单”。你告诉浏览器:脚本只能从哪些域名加载、图片只能从哪些域名加载、表单可以提交到哪里、页面能不能被嵌入 iframe。如果页面里出现了白名单之外的资源请求,浏览器直接拦截并在控制台报错。
一个常见的起点配置是这样:
nginx复制add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; object-src 'none'; base-uri 'self'; form-action 'self';" always;
这里每个指令都值得说清楚:
default-src 'self':所有没单独指定的资源类型,默认只允许从同源加载。这是 CSP 的地基,先把默认策略收紧,再逐个放宽。script-src 'self' 'unsafe-inline' 'unsafe-eval':脚本允许同源加载,同时允许内联脚本和 eval。说实话unsafe-inline和unsafe-eval是 CSP 里最敏感的两个词,如果业务代码里没有内联脚本,没有用new Function()或者 JSONP,建议果断删掉。但现实中很多老项目离不开它们,删了之后页面可能直接白屏,所以这里给的是一个“能跑起来的兼容方案”。img-src 'self' data::图片允许同源和 data URI。这个基本是标配,因为很多小图标和占位图会转成 base64。style-src 'self' 'unsafe-inline':样式允许同源和内联。内联样式几乎没办法完全禁掉,很多前端框架会在运行时往 DOM 里插 style 标签,所以这里默认放行。frame-ancestors 'self':这个指令和 X-Frame-Options 是同类,用来防点击劫持,后面会细说。它的优先级比 X-Frame-Options 更高,modern 浏览器都认这个。object-src 'none':禁止加载 flash 等插件资源。这个指令我建议所有站点都加上,因为 object 标签的利用面很广,但正常业务几乎用不到它。base-uri 'self':限制<base>标签的 URL。攻击者如果能篡改 base 标签,可以让页面上所有相对路径指向恶意域名,这个指令能堵住这个风险。form-action 'self':限制表单提交的地
