为什么我的Strict-Transport-Security头没有生效?
我在Nginx配置里加了Strict-Transport-Security: max-age=31536000;,但用在线工具检查发现这个头信息没出现。重启服务后还是没效果,配置文件放在server块里,其他安全头都正常显示…
server {
listen 443 ssl;
#...省略中间配置...
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
}
其他头像X-Content-Type-Options都能正常显示,唯独HSTS头完全看不到。难道是max-age格式写错了?或者需要配合其他配置?
add_header在 Nginx 里有个坑:它不会继承到 location 块里,而且如果某个 location 里也用了add_header,会覆盖掉 server 级别的配置。虽然你说放在 server 块里,但很多情况下,像 PHP、代理转发或者静态资源这些逻辑都在 location 里处理,一旦你在某个 location 里有自定义响应(比如 fastcgi 或 proxy_pass),并且那个 location 没有再次声明 HSTS 头,那这个头就会彻底消失。
重点是:Nginx 的
add_header是“全有或全无”的机制——只要你在某个作用域里用了它,就不会自动继承父级的头。解决办法很简单:
把 HSTS 这个头放到每个可能输出内容的 location 块里,或者更稳妥的做法是,在你的 server 块顶部加一个全局 include 文件来统一管理安全头。
不过最直接有效的做法是检查你有没有类似下面这样的结构:
改成:
或者更好的方式是抽成公共配置:
新建一个文件比如
security-headers.conf:然后在 server 和需要的安全 location 里 include 它:
另外注意一点:HSTS 只会在 HTTPS 响应中生效,如果你访问的是 HTTP,当然看不到。确保你是通过 HTTPS 访问再测。
还有个小建议:加上
includeSubDomains之后要谨慎,一旦下发,所有子域名都必须支持 HTTPS,否则会被浏览器直接拒绝访问,清不掉的。上线前确认好架构。最后用 curl 测一下:
curl -I https://yoursite.com看看返回头里有没有 Strict-Transport-Security。
注意安全,别让 HSTS 配错了把自己搞进黑名单里出不来。
HSTS的作用是强制浏览器后续访问使用HTTPS,所以它必须通过HTTPS连接才能被正确设置。确保你测试的是HTTPS连接,而不是HTTP。如果你用的是在线工具,请确认它们确实是通过HTTPS访问你的站点。
另外,max-age=31536000是标准推荐值,没有问题。includeSubDomains也是正确的用法。所以你的配置本身是没问题的。
还有一点容易忽略:某些Nginx版本或模块(比如旧版本或者OpenResty)可能会对add_header有影响,建议升级到最新稳定版。
推荐的做法是确保你的HTTPS配置正确,并且测试时始终使用HTTPS地址。可以用curl命令手动测试:
curl -I https://yourdomain.com
然后检查返回头中有没有Strict-Transport-Security。这样能更准确地验证配置是否生效。