大多数站点完成HTTPS证书部署后,仍会保留一条HTTP到HTTPS的重定向规则。但这条规则存在一个隐性缺口:用户在第一次访问时,如果中间人拦截了HTTP请求,仍可能被拖入钓鱼页面。HSTS(HTTP Strict Transport Security)就是用来封堵这个窗口的强制安全指令。而HSTS Preload则将这条指令写进浏览器内核,彻底消除初次访问的风险。
本文专注于全站HTTPS强制跳转与HSTS Preload预加载列表申请的完整流程。不讨论证书申请,不罗列商业CDN配置,只关注自建服务器或裸机部署下最务实的做法。
全站HTTPS强制跳转的底层逻辑
为什么简单重定向不够
大部分运维人员会在Nginx或Apache中写一条301规则,将80端口流量转到443。这确实能覆盖绝大多数正常访问,但存在两个问题:
- 首次请求暴露风险:用户输入example.com,浏览器默认走HTTP。这条请求在到达服务器之前,中间人可以篡改内容,甚至直接返回一个伪造的HTTPS证书错误提示,诱导用户放弃访问。
- SSL剥离攻击:攻击者利用代理将页面中所有https链接替换为http,使得后续请求全部降级。
301重定向只是“请用户走正门”,但门铃按钮仍在街上。HSTS的作用是告诉浏览器:“这个站点只允许HTTPS,以后你看到它的名字,直接走HTTPS,不要尝试HTTP。”
服务器端强制跳转配置(以Nginx为例)
配置要点:server块中监听80,返回301到HTTPS版本。但要注意保留对证书验证相关路径的放行(如.well-known/acme-challenge)。
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
Apache中类似:
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>
不要遗漏www域名与裸域名的统一。如果两者都服务,务必让其中一个作为权威域名,另一个301过去。否则HSTS头会因域名不一致而失效。
HSTS首部:Strict-Transport-Security
在HTTPS响应头中加入Strict-Transport-Security字段,告诉浏览器在指定时间内(max-age)必须通过HTTPS访问。典型值:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- max-age:单位秒,31536000即一年。建议至少半年。
- includeSubDomains:是否覆盖所有子域名。如果启用,务必确保所有子域名均支持HTTPS,否则子域将无法访问。
- preload:告诉浏览器“我准备申请预加载列表”,但该标记单独存在并不会自动加入列表,需要后续手动提交。
配置方法(Nginx):在443的server块中加入:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
验证方式:curl -I https://yourdomain.com | grep Strict
此时浏览器收到该头部后,会在本地缓存该策略。即使用户手动输入http,浏览器也会自动转为https。
HSTS Preload预加载列表是什么
缓存策略有一个盲区:第一次访问前,浏览器没有该站点的HSTS信息。Preload列表将域名硬编码进浏览器(Chrome/Firefox/Safari/Edge等),即使从未访问过,浏览器也默认只使用HTTPS。
这个列表由Chromium项目维护,每年更新几次。一旦域名成功加入,所有主流浏览器都会识别,新的访问请求从第一毫秒起就是HTTPS。
申请HSTS Preload的硬性条件
在提交前,必须逐条确认。任何一条不满足都会被拒绝,且提交后整改周期较长。
- 证书有效且链完整:不能有证书错误、过期、主机名不匹配。
- 所有子域名必须支持HTTPS:包括www、m、api等。如果某些子域只允许HTTP(比如开发环境),请关闭includeSubDomains。
- 根域名与www域名均需重定向到HTTPS:且重定向目标不能有HTTP。
- HSTS头部必须包含includeSubDomains和preload标记。
- max-age不小于10886400秒(18周),建议31536000。
- 检查是否有SSL/TLS漏洞:如RC4、TLS 1.0、弱密钥等会被拒绝。
- 所有重定向链必须全部走HTTPS:例如从 http://example.com -> https://example.com -> https://www.example.com,每一步都必须是HTTPS。
推荐使用官方检查工具预检。输入域名后,工具会列出所有未满足项。
申请步骤详解
第一步:确认域名所有权
在提交前,你需要在服务器上放置验证文件或使用DNS TXT记录证明你有权操作该域名。这是进入官方列表前的必要环节。
第二步:正式提交
访问hstspreload.org,点击“Submit your site”。输入域名,系统会再次检查。如果全部通过,会引导你完成验证。验证成功后,你的域名会进入待审核队列。
审核时间不定:以前是两周到两个月,近期由于审查收紧,有时需要三个月以上。审核期间不要修改HSTS配置,保持在线。
第三步:等待加入列表
你可以通过提交时留下的邮箱接收通知。也可以在hstspreload.org搜索域名查看状态。一旦显示“Preloaded”,恭喜你,域名已经被硬编码进浏览器。
风险与回滚:加入Preload前必须想清楚
最大的风险是:一旦加入Preload,你几乎无法撤销。因为浏览器更新周期长,即使你从列表中移除,用户设备上的预加载数据要到下次浏览器版本更新才会刷新。这意味着:
- 如果某天你的HTTPS证书失效,所有浏览器会直接拒绝访问,不再重试HTTP。
- 如果你需要临时关闭HTTPS做维护,用户端会报错且无法降级。
- 如果你要切换子域名结构,旧的includeSubDomains策略会锁死所有子域。
回滚方法:
- 从hstspreload.org申请移除(通过网站上的“Remove”功能)。
- 移除HSTS头部中的preload标记,并将max-age改为0,强制浏览器清除缓存:
Strict-Transport-Security: max-age=0 - 等待至少一个浏览器版本周期(通常6-12周)才能完全恢复HTTP访问。
务必先在不重要的测试域名上演练。生产环境强烈建议在确认所有子域、CDN、API都稳定HTTPS后再提交。
常见踩坑点与解决方案
- www与裸域不一致:很多人只给裸域跳转,但HSTS配置在www域上,导致www域访问正常但裸域HSTS头缺失。解决方案:统一处理,让两者都返回相同的HSTS头部。
- includeSubDomains过多:如果你有无法启用HTTPS的测试子域(如dev.example.com),则不能使用includeSubDomains,除非先让这些子域也支持HTTPS。可以考虑分开域名或使用通配符证书。
- CDN中转导致HSTS头丢失:如果使用了Cloudflare、CloudFront等CDN,需要在CDN层面添加HSTS头部,而非仅在源服务器。CDN可能会覆盖或删除源站的头。
- 重定向链中出现HTTP中间跳:比如 http://example.com -> http://www.example.com -> https://www.example.com,中间出现了HTTP。必须调整为全部HTTPS跳转。
总结
全站HTTPS强制跳转是基础,HSTS是加固,而Preload是终极方案。它们组合使用能彻底阻挡HTTP劫持与SSL剥离。但Preload的不可回滚特性要求站长在申请前做足功课。如果你正在运营一个面向用户的网站,且所有子域都已稳定HTTPS,那么申请Preload是值得的。否则,先用max-age较长的HSTS策略观察一段时间再说。
最后一条建议:不要为了追求“绿色锁”而盲目提交Preload。安全是逐步迭代的过程,比“一步到位”更重要的,是“可持续维护”。
延伸阅读
