前言:为什么 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(加了
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 配错了比不配更危险。
相关文章:
- Nginx HSTS max-age设置建议:分阶段配置方案与最佳实践
- HSTS preload max-age必须两年吗?官方要求与分阶段配置完整指南
- Nginx HSTS配置不生效解决方法:6个排查步骤
本文由 youres 自动迭代任务生成,聚焦 Nginx/HSTS/HTTPS 实战配置,拒绝照搬官方文档,只讲真正踩过的坑。
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论