为什么我的Strict-Transport-Security头没有生效?

Mr-秀云 阅读 25

我在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格式写错了?或者需要配合其他配置?

我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
南宫艳清
你这个 HSTS 头没生效,大概率是因为 add_header 在 Nginx 里有个坑:它不会继承到 location 块里,而且如果某个 location 里也用了 add_header,会覆盖掉 server 级别的配置。

虽然你说放在 server 块里,但很多情况下,像 PHP、代理转发或者静态资源这些逻辑都在 location 里处理,一旦你在某个 location 里有自定义响应(比如 fastcgi 或 proxy_pass),并且那个 location 没有再次声明 HSTS 头,那这个头就会彻底消失。

重点是:Nginx 的 add_header 是“全有或全无”的机制——只要你在某个作用域里用了它,就不会自动继承父级的头。

解决办法很简单:

把 HSTS 这个头放到每个可能输出内容的 location 块里,或者更稳妥的做法是,在你的 server 块顶部加一个全局 include 文件来统一管理安全头。

不过最直接有效的做法是检查你有没有类似下面这样的结构:

location / {
proxy_pass https://backend;
add_header X-Content-Type-Options nosniff;
# 注意!这里你只写了其他头,HSTS 就丢了
}


改成:

location / {
proxy_pass https://backend;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
}


或者更好的方式是抽成公共配置:

新建一个文件比如 security-headers.conf

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header Referrer-Policy no-referrer-when-downgrade;


然后在 server 和需要的安全 location 里 include 它:

server {
listen 443 ssl;
include security-headers.conf;

location /api {
include security-headers.conf;
proxy_pass http://upstream;
}
}


另外注意一点:HSTS 只会在 HTTPS 响应中生效,如果你访问的是 HTTP,当然看不到。确保你是通过 HTTPS 访问再测。

还有个小建议:加上 includeSubDomains 之后要谨慎,一旦下发,所有子域名都必须支持 HTTPS,否则会被浏览器直接拒绝访问,清不掉的。上线前确认好架构。

最后用 curl 测一下:
curl -I https://yoursite.com
看看返回头里有没有 Strict-Transport-Security。

注意安全,别让 HSTS 配错了把自己搞进黑名单里出不来。
点赞 6
2026-02-10 19:04
令狐秀玲
你的HSTS头没生效,是因为Nginx默认只会在HTTPS请求中添加HSTS头。从你的配置来看,你把add_header指令放在了listen 443的server块里,这没问题。但有个隐藏的“坑”:如果你的站点同时监听HTTP(80端口)和HTTPS(443端口),并且用户访问的是HTTP,这时候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。这样能更准确地验证配置是否生效。
点赞 2
2026-02-07 08:00