安全响应头是浏览器端安全防护体系中成本最低、收益最高的一环。它不需要修改任何业务代码,只需要在Nginx的server或location块中添加几行配置,就能有效防御XSS、点击劫持、MIME嗅探等常见攻击。但实际情况是,大量站点在做安全评估时,安全头这一项的得分惨不忍睹。本文将以Nginx为载体,系统讲解各安全头的原理、配置方法以及如何通过评估工具持续优化,最终拿到A+评级。

一、为什么安全响应头值得认真配置
安全响应头的工作方式很简单:服务器在HTTP响应中返回一些特定的头部字段,浏览器解析到这些字段后,会启用对应的防护机制。以X-Frame-Options为例,当响应中携带该头部且值为DENY时,浏览器会拒绝将该页面嵌入到任何iframe中,从而阻断点击劫持攻击。
这类防护的优势在于完全由浏览器侧执行,服务端只负责声明策略,性能开销几乎为零。相比在应用层做输入过滤、输出转义,安全头属于纵深防御的一层,它不能替代应用层的安全编码,但能在应用层被绕过时提供兜底保护。
业界最常用的评估工具是securityheaders.com,它会对目标站点做一次HTTP请求,根据返回的安全头情况给出从F到A+的评级。这个评级虽然不能完全代表站点安全水平,但它是安全审计报告中的常客,很多甲方验收和安全合规检查都会参考这个分数。
二、核心安全头逐一解析与Nginx配置
下面这些头部是评估工具重点检查的对象,我们逐个说明其作用和推荐配置。
1. Content-Security-Policy(内容安全策略)
CSP是所有安全头中功能最强也最复杂的一个。它通过白名单机制告诉浏览器:页面只能加载指定来源的脚本、样式、图片等资源,内联脚本默认被禁止。这直接切断了XSS攻击最常用的载荷注入路径。
一个相对稳妥的起步配置如下:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.ippipp.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'" always;
注意配置中的always关键字,它保证在404、500等错误响应中也会返回该头部,缺少这个关键字是评估失分的常见原因之一。另外,style-src中的'unsafe-inline'是因为大量前端框架会动态注入内联样式,待后续改造后再收紧。
2. Strict-Transport-Security(HSTS)
HSTS强制浏览器在指定时间内只用HTTPS访问站点,即使用户手动输入http://开头的地址,浏览器也会内部跳转到HTTPS,这就杜绝了SSL剥离攻击。配置示例:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
如果要申请加入浏览器的HSTS预加载列表,需要加上preload指令并把max-age设得足够长。但要特别谨慎:一旦进入预加载列表,短期内无法撤销,如果站点还有子域名依赖HTTP提供服务,加上includeSubDomains可能导致这些服务直接不可用。建议先小步验证,确认全站HTTPS覆盖后再逐步收紧。
3. 其余基础安全头
以下几项配置简单但缺一不可,它们在评估中各占一定分值:
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 "camera=(), microphone=(), geolocation=()" always; add_header X-XSS-Protection "0" always;
这里有个容易混淆的点:X-XSS-Protection现代浏览器已经废弃,甚至历史上其过滤器本身存在被利用的风险,因此推荐值为0(即关闭浏览器内置过滤器),让防护职责完全交给CSP。评估工具在新版规则中也认可值为0的写法。另外,CSP中的frame-ancestors指令是X-Frame-Options的现代替代品,两者同时配置可以兼顾旧浏览器。
三、一份完整的Nginx配置片段与评估调优
把上述内容整合起来,放在server块中即可生效。完整示例如下:
server {
listen 443 ssl http2;
server_name www.ipipp.com;
# SSL相关配置省略
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
location / {
root /usr/share/nginx/html;
index index.html;
}
}配置完成后执行nginx -t检查语法,再通过nginx -s reload平滑重载,然后到securityheaders.com输入域名重新评分。
调优过程中有几个高频踩坑点需要留意。第一个是add_header的继承问题:Nginx中location块内一旦出现任何add_header指令,就会继承失效,server块中定义的所有安全头在该location中全部丢失。解决办法是把安全头统一写在一个include文件中,在需要的location里显式引入,或者使用全局配置。第二个是CSP策略过严导致页面白屏或样式丢失,推荐先用Content-Security-Policy-Report-Only头部以报告模式运行一段时间,结合浏览器控制台的违规报告逐步收紧白名单,确认无误后再切换到强制模式。
第三个是升级到A+的关键。在拿到A级之后,评估工具要求CSP策略中不包含unsafe-inline和unsafe-eval(对script-src而言),并且HSTS的max-age要达到一定阈值。要彻底移除内联脚本,需要对业务代码做改造,把内联事件处理和内联脚本标签外移为独立文件,或者使用nonce机制:每次响应生成随机nonce,脚本标签带上该值,CSP中通过script-src 'self' 'nonce-随机值'放行。这需要Nginx与后端配合,或者借助Nginx的njs模块动态生成。
四、持续评估与运维建议
安全头配置不是一次性工作。随着业务迭代,新增的第三方脚本、广告代码、统计SDK都可能触发CSP违规,需要定期回顾白名单是否过于宽松。建议把securityheaders.com的评分检查纳入上线流程,也可以在CI/CD流水线中用curl抓取响应头做自动化断言:
curl -sI https://www.ipipp.com | grep -i "content-security-policy" curl -sI https://www.ipipp.com | grep -i "strict-transport-security"
两条命令有输出且值符合预期,说明关键头部仍在生效。还可以配合开源工具如securityheaders的本地化实现,在内网环境中做同样的扫描。
总结一下实施路径:先补齐基础安全头把评级拉到C以上,再配置合理的CSP和HSTS冲到A,最后通过消除内联脚本、引入nonce机制完成A+的最后一步。整个过程遵循先报告模式验证、再强制生效的原则,既能快速提升评级,又能避免因策略过严导致的线上故障。安全头虽然只是纵深防御的一层,但它配置成本低、见效快,是每个Nginx运维人员和后端开发者都应该掌握的基本功。
Nginx安全头配置CSP内容安全策略HTTP安全响应头修改时间:2026-09-12 08:06:34