0

HSTS预加载列表提交失败原因:7个常见问题及解决办法

2026.05.25 | youres | 12次围观

目录

什么是HSTS预加载列表

HSTS Preload List是由各大浏览器厂商维护的一组域名清单。一旦你的域名被加入这个列表,浏览器会直接通过HTTPS访问你的网站,即使用户在地址栏输入的是http://。这意味着你的域名从根本上杜绝了HTTP明文访问的可能性。

目前主流浏览器(Chrome、Firefox、Edge、Safari)都内置了这个列表。提交入口是 hstspreload.org,提交后通常需要数周到数月才能在所有浏览器中生效。

但很多站长在提交时遇到了各种报错,导致提交被拒。这篇文章把最常见的原因总结出来,帮你一次性排查到位。

提交HSTS预加载的前提条件

在提交之前,你的HSTS响应头必须满足以下全部条件:

  • max-age 至少 31536000 秒(一年)
  • 包含 includeSubDomains 指令
  • 包含 preload 指令
  • 响应头必须通过HTTPS返回(HTTP响应头会被忽略)
  • 根域名和www子域名都必须正确返回HSTS头

正确的HSTS响应头示例:

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

以上任何一条不满足,提交都会失败。下面具体看失败的原因。

提交失败的7个常见原因

1. max-age值不够大

这是最基础的错误。HSTS预加载列表要求 max-age 至少为 31536000(1年)。如果你设置了较短的时间用于测试(比如 max-age=300),测试完忘记改回来,提交就会直接被拒。

解决办法:确认生产环境的 max-age 不小于 31536000。如果之前用了短值做测试,改回来后需要等待一段时间再提交。

2. 缺少 includeSubDomains 指令

预加载列表要求你的HSTS策略覆盖所有子域名,因此 includeSubDomains 是必选项,不是可选项。

缺少这个指令时,hstspreload.org会提示 "HSTS header does not contain includeSubDomains"。

解决办法:在Nginx配置中加上 includeSubDomains

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

3. 缺少 preload 指令

这个容易被忽略。你想加入预加载列表,就必须显式声明 preload。浏览器厂商认为这应该是一个深思熟虑的决定,所以需要你主动声明"我确实要加入预加载"。

解决办法:在HSTS头的末尾加上 preload,注意用分号分隔。

4. HTTP页面也返回了HSTS头

这是一个很隐蔽的问题。如果HTTP页面(非HTTPS)也返回了HSTS响应头,提交会被拒绝。HSTS头应该只在HTTPS响应中返回。

在Nginx中,这个问题通常出现在同时监听80和443端口的server块中,80端口的location也继承了 add_header 指令。

解决办法:确保80端口只做重定向,不输出HSTS头:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com www.example.com;
    # HSTS头只在这里设置
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}

5. www子域名未正确配置HSTS

预加载列表提交时会检查根域名和 www 子域名。如果 www.example.com 没有返回正确的HSTS头,或者指向了不同的服务器且那台服务器没有配置HSTS,提交就会失败。

解决办法:确保根域名和www子域名都:

  • 启用了HTTPS
  • 返回了完整的HSTS头(包含三个必填指令)
  • HTTP请求正确重定向到HTTPS

6. HSTS头被重复设置或被覆盖

Nginx的 add_header 指令有一个容易踩的坑:如果子级location块中也使用了 add_header,父级的 add_header 指令会被完全覆盖,而不是追加。

比如你在server块设了HSTS头,但在某个location里设了CSP头,结果那个location返回的响应里HSTS头就没了。

解决办法:使用 always 参数,并检查是否在子级location中覆盖了header。更推荐的方式是使用 headers-more-nginx-module 模块,它不受继承规则限制。

7. 链式重定向导致HSTS头丢失

如果你的域名经过了多次重定向(比如 http://https://https://www.),中间的某一次重定向跳转可能导致最终页面的HSTS头没有被浏览器接收到。

这种情况在Cloudflare等CDN与源站混用的场景中很常见。

解决办法:简化重定向链,尽量做到一步到位。避免 HTTP → HTTPS → www 三步跳转,直接合并为两步或一步。

提交失败后的排查步骤

按照以下顺序逐一排查,能覆盖90%以上的失败原因:

  1. 用curl验证HSTS头:对根域名和www子域名分别执行 curl -sI https://你的域名,检查响应头中是否包含完整的HSTS头
  2. 检查HTTP响应:执行 curl -sI http://你的域名,确认HTTP页面不返回HSTS头
  3. 在线检测:访问 hstspreload.org,在 "Domain" 框中输入域名,点击 "Check status" 查看详细检测结果
  4. 检查所有子域名:如果有重要的子域名(如API、管理后台),确认它们也能正常使用HTTPS
  5. 清除浏览器缓存后重试:有时候检测结果会被缓存,等几分钟再提交

成功提交后的注意事项

  • 提交后不可轻易撤销:从预加载列表移除需要很长时间(Chrome约30-70周,Firefox约52周),务必在提交前充分测试
  • 必须持续维护HTTPS:一旦加入预加载列表,如果HTTPS证书过期或服务器无法通过HTTPS访问,用户将完全无法访问你的网站
  • 关注CDN配置:使用CDN时,确保CDN也正确转发了HSTS头,否则源站的配置在CDN层面会被覆盖
  • 定期检查状态:在 hstspreload.org 上定期查询域名状态,确认预加载是否已生效

相关文章推荐

版权声明

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

发表评论
883文章数 0评论数
作者其它文章