<meta http-equiv="Strict-Transport-Security">完全无效,因RFC 6797明确禁止HTML设置HSTS,该策略必须由服务器在有效HTTPS响应头中发送;浏览器在TLS握手完成前已需注册策略,而<meta>标签在HTML解析阶段才处理,此时明文连接早已建立,所有主流浏览器均直接忽略。

为什么完全无效
浏览器根本不会解析 <meta http-equiv="Strict-Transport-Security"> —— RFC 6797 明确禁止,所有主流浏览器(Chrome、Firefox、Edge、Safari)均无视该标签。原因很直接:Strict-Transport-Security 是 HTTP 协议层机制,不是 HTML 渲染行为。用户首次访问 http://example.com 时,请求走的是明文 HTTP,服务器连 TLS 握手都没完成,index.html 文件都还没发出去,更不可能执行任何 meta 标签逻辑。
常见错误现象:在 index.html 里写了 meta 标签,用 curl -I https://example.com 查不到头,浏览器开发者工具 Network 面板也看不到 Strict-Transport-Security 字段——这说明策略根本没生效,不是“延迟生效”,而是压根没被发送。
Nginx 中 add_header Strict-Transport-Security 的正确位置和参数
HSTS 头必须加在 listen 443 ssl 的 server 块顶层,且必须带 always 参数。否则在 304 响应、静态资源缓存或子 location 块中极易丢失。
-
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;—— 这行必须放在server { ... }内,不能塞进location ~ \.html$或location /里 - 如果用了 CDN(如 Cloudflare),要确认它未覆盖或删除该 header;Cloudflare 默认透传,但若开启“Always Use HTTPS”又关掉“HSTS”,反而会干扰
-
preload参数需谨慎:一旦加上并提交到 hstspreload.org,就无法快速撤回;上线前务必先用max-age=300测试 24 小时
Apache 中 Header always set 的启用前提与常见失效点
Apache 必须加载 mod_headers 模块,且仅在 <VirtualHost *:443> 块内设置才有效。HTTP(80端口)配置里加这行,浏览器收不到,还会白加。
立即学习“前端免费学习笔记(深入)”;
验证步骤缺一不可:
- 运行
apachectl -M | grep headers,无输出就得在httpd.conf里取消注释LoadModule headers_module modules/mod_headers.so - 用
curl -I https://yourdomain.com确认响应头含Strict-Transport-Security,而不是只看到Location或空响应 - 检查是否误写成
Header set(漏了always)——这会导致 304 响应不带 HSTS 头,浏览器下次访问可能降级
HSTS 生效的两个硬性依赖:重定向 + 证书有效性
HSTS 不是独立开关,它依赖两个服务端基础条件同时成立:一是 http:// 请求必须 301 跳转到 https://,二是 HTTPS 响应必须由有效、可信证书支撑。任一缺失,HSTS 就形同虚设。
典型失效场景:
- 只配了 HSTS 头,但
listen 80server 块没写return 301 https://$host$request_uri;→ 用户输http://直接报错或被劫持 - 证书过期、域名不匹配、或用自签名证书 → 浏览器拒绝接收 HSTS 指令,即使响应头存在也无视
- 子域名 HTTPS 未全量覆盖,却开了
includeSubDomains→api.example.com若仍走 HTTP,整个主域 HSTS 会被浏览器丢弃
真正麻烦的不是配置本身,而是依赖链:HSTS 头只是最后一环,前面每一步(重定向、证书、子域 HTTPS 覆盖)都要稳,它才敢记进浏览器内存。稍有松动,用户首次访问就可能掉进中间人陷阱。



















