Nginx 配置 HSTS 头部后导致部分旧浏览器无法访问怎么解决?

文章导读
先说结论:这不是浏览器故障,而是安全策略与客户端能力不匹配。优先恢复访问,但严禁为兼容旧浏览器而降低 TLS 安全标准。
📋 目录
  1. 核心原因分析
  2. 紧急恢复步骤
  3. 特殊场景处理
  4. 验证与排查
  5. 常见坑与风险
  6. 参考来源
A A

先说结论:这不是浏览器故障,而是安全策略与客户端能力不匹配。优先恢复访问,但严禁为兼容旧浏览器而降低 TLS 安全标准。

  • 紧急恢复:临时注释 HSTS 配置或缩短 max-age,重载 Nginx。
  • 安全底线:生产环境严禁开启 TLSv1.0/1.1,旧浏览器应升级而非服务器降级。
  • 特殊场景:若域名在 HSTS 预加载列表,需官方申请移除,仅改配置无效。
  • 验证必要:修改后务必清除浏览器本地 HSTS 缓存再测试。

核心原因分析

HSTS(HTTP Strict Transport Security)强制浏览器通过 HTTPS 连接,且忽略证书错误。旧浏览器无法访问通常由以下两个原因叠加导致:

  1. 本地策略缓存:浏览器曾接收过 HSTS 头部,在 max-age 有效期内强制跳转 HTTPS,即使服务端已移除配置,本地缓存仍生效。
  2. TLS 握手失败:旧浏览器可能不支持 TLS 1.2 及以上版本。若服务端仅启用高版本 TLS,握手直接中断,且因 HSTS 策略用户无法点击“继续访问”。

紧急恢复步骤

第一步:备份当前配置
修改前务必备份,防止配置错误导致服务不可用。

cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
cp /etc/nginx/conf.d/your_site.conf /etc/nginx/conf.d/your_site.conf.bak

第二步:调整 HSTS 配置
临时注释掉 HSTS 头部,或大幅缩短有效期以便策略快速过期。

Nginx 配置 HSTS 头部后导致部分旧浏览器无法访问怎么解决?
server {
    listen 443 ssl;
    server_name example.com;

    # 方案 A:临时关闭(推荐用于紧急恢复)
    # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # 方案 B:缩短有效期为 1 天(单位秒),便于后续重新启用
    # add_header Strict-Transport-Security "max-age=86400" always;
}

第三步:检查 TLS 协议版本(安全红线)
生产环境必须禁用 TLSv1.0 和 TLSv1.1,这两种协议存在 POODLE、BEAST 等高危漏洞。旧浏览器无法访问的根本解决方案是升级客户端,而非服务器降级。

# 安全配置:仅启用 TLSv1.2 和 TLSv1.3
ssl_protocols TLSv1.2 TLSv1.3;

# 配套加密套件建议
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;

第四步:重载服务
测试配置语法无误后重载。

nginx -t && nginx -s reload

特殊场景处理

1. 域名在 HSTS 预加载列表(Preload List)

如果域名曾提交到 Chrome 等浏览器的 HSTS 预加载列表,即使服务端移除头部,浏览器也会强制 HTTPS。这种情况无法通过 Nginx 配置撤销。

解决方法:

Nginx 配置 HSTS 头部后导致部分旧浏览器无法访问怎么解决?
  1. 访问 hstspreload.org 查询域名状态。
  2. 若显示 "Pending Removal" 或 "Preloaded",需在同一页面提交移除申请。
  3. 等待浏览器更新列表(通常需数周),期间用户需手动清除本地缓存。

2. 过渡方案:基于 User-Agent 差异化配置

若必须支持无法升级的旧设备(如内网特定终端),可通过 Nginx map 指令识别 User-Agent,仅对现代浏览器发送 HSTS 头部。

http {
    # 定义映射规则,旧浏览器不启用 HSTS
    map $http_user_agent $hsts_policy {
        default "max-age=31536000; includeSubDomains";
        ~*"MSIE [6-9]" "";
        ~*"Android.*[2-4]" "";
    }

    server {
        listen 443 ssl;
        # 动态添加头部,若 $hsts_policy 为空则不发送
        add_header Strict-Transport-Security $hsts_policy always;
    }
}

注意:此方案会降低部分用户的安全性,仅建议在受控内网或过渡期使用,公网服务应强制要求客户端升级。

验证与排查

1. 检查响应头
使用 curl 命令查看头部是否已变更或消失。

Nginx 配置 HSTS 头部后导致部分旧浏览器无法访问怎么解决?
curl -I https://example.com

若已移除,响应头中不应再包含 Strict-Transport-Security 字段。

2. 清除浏览器本地 HSTS 缓存
服务端配置生效后,旧浏览器可能仍记忆策略。Chrome 清除步骤:

  1. 地址栏输入 chrome://net-internals/#hsts
  2. 在 "Delete domain security policies" 输入域名。
  3. 点击 "Delete" 按钮。
  4. 重启浏览器测试 HTTP 访问。

3. 开发者工具排查
打开浏览器控制台网络面板,查看请求是否被 307 内部跳转。若状态码为 307 Internal Redirect 且无法取消,说明本地 HSTS 缓存未清除。

常见坑与风险

  • includeSubDomains 影响范围:开启该选项后,所有子域名都会强制 HTTPS。若某些子域名尚未配置 SSL,会导致大面积无法访问。
  • max-age 设置过长:一旦设置过长(如一年),在配置错误期间,所有访问过 site 的用户都会在很长一段时间内无法通过 HTTP 访问,回滚成本高。建议初始设置较小值(如 1 天)。
  • HTTP 端也发送 HSTS:HSTS 头部必须在 HTTPS 响应中发送才有效且安全。若在 HTTP 端口发送,容易被中间人攻击剥离。

参考来源

  • MDN Web Docs: Strict-Transport-Security - https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Strict-Transport-Security
  • Nginx Documentation: ngx_http_ssl_module - https://nginx.org/en/docs/http/ngx_http_ssl_module.html
  • RFC 6797: HTTP Strict Transport Security (HSTS) - https://datatracker.ietf.org/doc/html/rfc6797
  • HSTS Preload List Submission - https://hstspreload.org/