hsts需手动在https响应头中设置strict-transport-security,必须用set()而非add(),且仅对https请求生效;上线前须用max-age=300灰度验证,确认无证书错误、子域https就绪及301跳转带hsts头后,方可延长至31536000秒。

HSTS 不是开个 HTTPS 服务就自动生效的,必须手动在每个 HTTPS 响应里写入 Strict-Transport-Security 头,否则浏览器根本不会记住“只许走 HTTPS”这条规则。
Go 标准库 http.Server 怎么加 HSTS 头
标准库不提供自动 HSTS,你得自己在 handler 里调用 w.Header().Set()。关键点有三个:
-
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")必须在任何w.Write()或w.WriteHeader()之前执行,否则头会被丢弃 - 别用
Add()—— 它可能重复添加,导致浏览器忽略整个头;Set()才能确保唯一性 - 只对 HTTPS 请求设:检查
r.TLS != nil,但更可靠的是依赖反向代理传来的r.Header.Get("X-Forwarded-Proto") == "https"(尤其当你用 Nginx 终止 TLS 时)
Gin 框架中设置 HSTS 的正确时机
Gin 的中间件里,c.Header() 在 c.Next() 后仍可写,但 HSTS 必须在响应发出前锁定。推荐写法:
- 在中间件开头调用
c.Header("Strict-Transport-Security", value),且放在c.Next()之前 - 避免多层中间件叠加:先查
c.Response().Header().Get("Strict-Transport-Security")是否已存在,非空就跳过 - 重定向也要带 HSTS:比如用
c.Redirect(http.StatusMovedPermanently, "/new")前,同样要先设头,否则跳转后的首屏不生效
为什么 max-age=300 是上线前必测的底线
设成 31536000(1 年)后,一旦出错,用户端无法远程清除,只能等时间过期或手动进 chrome://net-internals/#hsts 删除。所以:
- 开发/测试环境一律用
max-age=300(5 分钟),验证浏览器是否真能自动把http://改成https:// - 确认全站无 HTTP 资源(图片、脚本、iframe)、所有子域 HTTPS 就绪、且根域名
example.com的 301 跳转响应也带 HSTS 头,才敢升到 31536000 -
preload参数不是加了就进浏览器预加载列表——必须先去hstspreload.org提交并通过校验,否则它只是个无效字符串
最易被忽略的一点:HSTS 只保护“后续访问”,对用户第一次手输 http:// 无能为力。所以 HTTP 端口的 301 跳转不能少,且必须是 return 301 https://$host$request_uri 这种原生跳转,不是 rewrite,也不是 302。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











