HSTS(HTTP Strict Transport Security)是一个安全响应头,告诉浏览器始终通过 HTTPS 连接——即使用户输入 http:// 或点击 HTTP 链接。浏览器一旦收到 HSTS 头,就会自动将该域名的所有未来请求升级为 HTTPS,防止降级攻击和不安全连接。
为什么 HSTS 很重要
没有 HSTS 时,对你站点的首次请求可能是 HTTP(在 301 重定向生效之前)。在这个短暂窗口内,网络上的攻击者可以:
- 剥离 HTTPS —— 拦截重定向并让用户停留在 HTTP(SSL 剥离攻击)
- 窃取 Cookie —— 如果 Cookie 在初始 HTTP 请求中发送
- 注入内容 —— 修改重定向响应
HSTS 消除了这个窗口。首次 HTTPS 访问后,浏览器不再尝试 HTTP。
如何启用 HSTS
Nginx
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
将此添加到 HTTPS server 块(端口 443)中,不是 HTTP 重定向块。
Apache
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
需要 mod_headers(sudo a2enmod headers)。
Cloudflare
Dashboard → SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS) → Enable。
HSTS 参数
| 参数 | 示例 | 含义 |
|---|---|---|
max-age | 63072000(2 年) | 浏览器记住使用 HTTPS 的时长(秒) |
includeSubDomains | — | 将 HSTS 同时应用于所有子域名 |
preload | — | 表明意图加入 HSTS 预加载列表 |
选择 max-age
| 阶段 | max-age | 目的 |
|---|---|---|
| 测试 | 300(5 分钟) | 在承诺之前验证 HTTPS 正常工作 |
| 确认 | 604800(1 周) | 如需回滚风险较低 |
| 生产 | 31536000(1 年) | 标准推荐 |
| 长期 | 63072000(2 年) | 预加载列表要求 |
从小值开始,逐步增加。 如果 HTTPS 在长 max-age 缓存期间出现故障,访问者将完全无法访问你的网站——浏览器拒绝通过 HTTP 连接。
HSTS 预加载
HSTS 预加载列表是硬编码在浏览器中的域名列表,始终使用 HTTPS,即使是第一次访问(在收到任何 HSTS 头之前)。
预加载的要求
- 提供有效的 HTTPS 证书
- 在同一主机上将 HTTP 重定向到 HTTPS
- HSTS 头的
max-age≥ 63072000(2 年) - 包含
includeSubDomains指令 - 包含
preload指令
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
提交预加载
前往 hstspreload.org,输入你的域名并提交。审核后(数周到数月),你的域名将被添加到浏览器内置列表中。
预加载的注意事项
- 很难撤销。 从预加载列表移除需要数月时间,并需要浏览器发布一个新版本。在此期间,你的域名只能通过 HTTPS 访问。
includeSubDomains是强制的 —— 所有子域名都必须支持 HTTPS。如果staging.example.com没有证书,它将变得不可访问。- 只有当你确信所有当前和未来的子域名都支持 HTTPS 时才进行预加载。
常见错误
在 HTTP 响应中设置 HSTS
HSTS 必须仅在 HTTPS 上发送。如果你的 HTTP 重定向也发送了 HSTS 头,浏览器会忽略它(规范要求 HTTPS)。只在端口 443 的块中设置该头。
忘记子域名
includeSubDomains 将 HSTS 应用于所有子域名。如果 internal.example.com 没有 HTTPS,它将变得不可达。启用前审计所有子域名。
过早设置过高的 max-age
如果 HTTPS 出故障(证书过期、配置错误),访问者无法回退到 HTTP。浏览器拒绝连接。先设 5 分钟,验证一切正常,然后再增加到 1 年。
如何检查 HSTS 是否生效
curl -sI https://yourdomain.com | grep -i strict-transport
# Expected: strict-transport-security: max-age=63072000; includeSubDomains
在 Chrome DevTools 中:Network 标签 → 点击请求 → Headers → 查找 Strict-Transport-Security。
常见问题
HSTS 能替代 HTTP→HTTPS 重定向吗?
不能。HSTS 和重定向服务于不同目的。重定向捕获首次 HTTP 请求。HSTS 告诉浏览器以后不再发起 HTTP 请求(在首次 HTTPS 访问之后)。两者都需要。
HSTS 会导致问题吗?
会,如果 HTTPS 出故障的话。使用长 max-age 时,浏览器拒绝将 HTTP 作为回退。这就是为什么应该从短 max-age 开始,只有在 HTTPS 稳定后才增加。
如果我在 Cloudflare 上还需要 HSTS 吗?
Cloudflare 处理访客→Cloudflare 的连接,但在源站启用 HSTS 保护完整链路。通过 Cloudflare 面板为边缘启用 HSTS,如果使用 Full (Strict) 模式,也在源站启用。
HSTS 和 upgrade-insecure-requests CSP 指令有什么区别?
upgrade-insecure-requests 告诉浏览器通过 HTTPS 而非 HTTP 加载子资源(图片、脚本)——修复混合内容。HSTS 告诉浏览器始终对整个域名使用 HTTPS。它们解决不同问题,可以同时使用。