Echo默认不发Strict-Transport-Security头,因其不自动判断HTTPS环境、不检查r.TLS,且HTTP下发送该头会被浏览器忽略甚至引发兼容问题;必须手动添加条件判断,仅在TLS成立或可信反代(X-Forwarded-Proto: https)且非本地开发时注入。

为什么 Echo 默认不发 Strict-Transport-Security 头
Echo 是一个极简 HTTP 路由器,echo.New() 启动的服务不会自动添加任何安全响应头——包括 Strict-Transport-Security。它不判断你是否在 HTTPS 下运行,也不检查 r.TLS 是否为 nil。如果你直接在 HTTP 环境下发这个头,浏览器会静默忽略;更糟的是,某些旧客户端可能因此拒绝后续 HTTPS 请求。
必须手动加、必须条件判断、必须只在 TLS 连接成立时才写入。
-
Strict-Transport-Security只对 HTTPS 有效,HTTP 响应中设置等于无效甚至有害 - 本地开发用
localhost或127.0.0.1:8080时,r.TLS == nil为真,此时绝不能写该头 - 即使部署了反向代理(如 Nginx),也要确保 Echo 能感知到 TLS——通常靠
X-Forwarded-Proto: https+echo.HTTPErrorHandler中校验
echo.MiddlewareSecure 能否替代手写 HSTS
可以,但有前提:它默认启用 Strict-Transport-Security,但参数固定为 max-age=31536000; includeSubDomains,且不带 preload。更重要的是,它**不自动跳转 HTTP → HTTPS**,也不校验转发头。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
如果你用 Nginx 做 TLS 终止,Echo 收到的是 HTTP 请求,echo.MiddlewareSecure 就不会触发 HSTS —— 它只看 r.TLS != nil,而这个字段在反代后是空的。
- 要让它生效,必须显式启用信任代理:
e := echo.New(); e.Pre(middleware.ProxyHeaders) -
echo.MiddlewareSecure会同时加X-Content-Type-Options和X-Frame-Options,但不会加Content-Security-Policy - 若需
preload,必须绕过中间件,自己写echo.Use(func(next echo.Handler) echo.Handler { ... })手动注入
如何在 Echo 中安全地注入 HSTS 头(含反代兼容)
最稳妥的方式是写一个轻量中间件,在 r.TLS != nil 或 r.Header.Get("X-Forwarded-Proto") == "https" 成立时才写头,并排除 localhost。
func hstsMiddleware() echo.MiddlewareFunc {
return func(next echo.Handler) echo.Handler {
return func(c echo.Context) error {
req := c.Request()
// 只在真实 HTTPS 或可信反代下启用
isHTTPS := req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https"
host := req.Host
// 排除本地开发地址
if !isHTTPS || strings.HasPrefix(host, "localhost:") || host == "localhost" || strings.HasSuffix(host, ":8080") {
return next(c)
}
c.Response().Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
return next(c)
}
}
}
- 务必在
echo.New()后立即注册:e.Use(hstsMiddleware()) - 若使用 Nginx,确保其转发头已开启:
proxy_set_header X-Forwarded-Proto $scheme; -
preload加入后,需主动提交至 hstspreload.org,否则无实际效果
HSTS 配置后容易被忽略的三个现实问题
一旦设了 max-age=31536000,浏览器会在一年内强制 HTTPS,期间任何证书错误(如自签名、域名不匹配、过期)都会导致整个站点不可访问——用户无法点击“高级→继续访问”。
- 测试阶段切忌直接上
preload,先用max-age=300(5 分钟)验证流程 - 子域名未全部支持 HTTPS 时,不要加
includeSubDomains,否则dev.example.com会连不上 - 证书轮换窗口期必须重叠:新证书生效前,旧证书不能过期;否则 HSTS 会卡死所有访问

















