0

Nginx HSTS max-age测试值和正式值切换方案:分阶段配置让HTTPS安全策略稳稳落地

2026.05.31 | youres | 3次围观

前言:为什么 max-age 不能一上来就设两年

HSTS(HTTP Strict Transport Security)的 max-age 参数决定浏览器记住"强制 HTTPS"指令的时间。设短了,安全效果打折扣;设长了,一旦证书或 HTTPS 配置出问题,用户在有效期内无法访问你的网站。

很多教程上来就让你直接设 max-age=63072000(两年),这是 HSTS preload 的提交要求,不是你第一天就该用的值。

正确的做法:分阶段切换,从短到长,每一步都验证无误后再加码。


一、max-age 的三个阶段:测试 → 过渡 → 正式

阶段一:测试值(建议 300~3600 秒)

适用场景: 第一次启用 HSTS,或者刚刚改过 HTTPS 配置。

推荐值:

Strict-Transport-Security: max-age=300

(5分钟,足够你测试浏览器是否正常工作)

这个阶段要验证什么:

  • 浏览器是否能正常访问 HTTPS 页面
  • 有没有混合内容(Mixed Content)报错
  • 子域名是否也能正常加载(如果准备加 includeSubDomains

验证方法:

# Chrome 访问 chrome://net-internals/#hsts
# 在 Query HSTS/PKP 输入框里输入你的域名
# 看 static_hsts 和 dynamic_hsts 的输出

# 或者用 curl 验证响应头
curl -I https://www.youres.cn

阶段二:过渡值(建议 86400~604800 秒)

适用场景: 测试值验证通过后,准备向正式值过渡。

推荐值:

Strict-Transport-Security: max-age=86400

(1天,足够覆盖大部分用户的访问周期)

这个阶段让一部分回访用户真正"感受"到 HSTS 的效果,同时如果出问题,最多1天后浏览器会自动退回到允许 HTTP。

Nginx 配置示例:

# 只加 max-age,先不急着加 includeSubDomains 和 preload
add_header Strict-Transport-Security "max-age=86400" always;

阶段三:正式值(建议 31536000 秒起)

适用场景: 过渡值稳定运行一段时间后(建议至少1~2周),确认没有问题。

推荐值:

Strict-Transport-Security: max-age=31536000

(1年,这是很多大厂的正式值)

如果准备提交 HSTS Preload 列表,则需要:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

(两年 + 包含所有子域名 + 预加载标记)


二、分阶段切换的完整 Nginx 配置示例

第一步:测试值配置(第1~3天)

server {
    listen 443 ssl http2;
    server_name www.youres.cn;

    # SSL 配置省略...

    # 测试值:5分钟
    add_header Strict-Transport-Security "max-age=300" always;
}

验证浏览器已记住:

curl -I https://www.youres.cn 2>/dev/null | grep -i strict
# 输出:strict-transport-security: max-age=300

第二步:过渡到 1天(第4~7天)

add_header Strict-Transport-Security "max-age=86400" always;

注意: 浏览器会用较大的那个值覆盖。也就是说,如果之前用户收到的是 max-age=300,现在收到 max-age=86400,浏览器会更新为 86400,不需要手动清除 HSTS 缓存

第三步:正式值 1年(第2周起)

add_header Strict-Transport-Security "max-age=31536000" always;

第四步(可选):提交 HSTS Preload

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

提交地址:https://hstspreload.org

提交前必须确认三件事:

  • 所有子域名都已支持 HTTPS(加了 includeSubDomains 后,子域名走 HTTP 会直接无法访问)
  • 网站可以长期维护 HTTPS 配置(提交后想撤销非常麻烦)
  • max-age 确实 ≥ 63072000

三、从测试值切换到正式值,浏览器会怎样?

这是最多人问的问题,直接给结论:

场景浏览器行为
测试值 max-age=300,切换为 max-age=86400浏览器用新值覆盖旧值,无需手动清除缓存
正式值 max-age=31536000,想降级为更短的值发送新的较小 max-age,浏览器会更新为较小值
想彻底让浏览器"忘记"HSTS发送 max-age=0,浏览器会立即清除

重要: 如果你想回退 max-age,不能只改 Nginx 配置就完事——已经记住 HSTS 的浏览器不会主动来取新的响应头,除非等它过期,或者手动清除 HSTS 缓存。

正确回退方式:

# 先发 max-age=0 让浏览器清除
add_header Strict-Transport-Security "max-age=0" always;

等所有用户的浏览器都"刷新"过一次之后(通常需要等一个 max-age 周期),再完全移除 HSTS 头。


四、常见问题排查

问题1:加了 HSTS 后,浏览器仍然走 HTTP?

原因: HSTS 头只通过 HTTPS 连接传递。用户第一次访问 http://example.com 时,浏览器根本不会收到 HSTS 头,所以还是会走 HTTP。

解决: 配置 HTTP 到 HTTPS 的 301 重定向,让用户第一次就被重定向到 HTTPS,从而收到 HSTS 头。

server {
    listen 80;
    server_name www.youres.cn;
    return 301 https://$server_name$request_uri;
}

问题2:includeSubDomains 加上后,子域名访问不了?

原因: 子域名没有配置 HTTPS,或者证书不对。

解决: 先确认所有子域名都能正常走 HTTPS,再在 HSTS 头里加 includeSubDomains

问题3:提交 HSTS Preload 被拒,提示 max-age 不够?

原因: hstspreload.org 要求 max-age ≥ 63072000(两年)。

解决: 先把 max-age 改为 63072000,等 Chrome 拿到新值后(用户访问一次即可),再重新提交。


五、总结:一套稳妥的切换时间表

时间max-age 值验证重点
第1~3天300(5分钟)确认 HTTPS 正常,无混合内容报错
第4~7天86400(1天)确认回访用户无异常
第2周起31536000(1年)稳定运行,准备 Preload
第4周(可选)63072000 + includeSubDomains + preload提交 hstspreload.org

核心原则: 每切换一次,至少观察一个当前 max-age 的周期,再继续加码。不要急,HSTS 配错了比不配更危险。


相关文章:


本文由 youres 自动迭代任务生成,聚焦 Nginx/HSTS/HTTPS 实战配置,拒绝照搬官方文档,只讲真正踩过的坑。

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论