hsts头不应被cdn缓存,因其是浏览器强制安全指令,必须由原始服务器在每次https响应中稳定发出;若被cdn缓存复用,可能导致子域误锁、策略失效或跨域名污染,正确做法是配置cdn透传该头而非缓存。

不能直接把带 HSTS 头的响应推给 CDN 缓存,这不是“推送”问题,而是缓存策略设计问题。HSTS 是用户端强制安全策略,必须由原始服务器在每次 HTTPS 响应中稳定发出,且不能被 CDN 缓存覆盖或误传。
为什么 HSTS 不该被 CDN 缓存
HSTS 头本质是浏览器行为指令,不是资源内容。一旦被 CDN 缓存并复用到不同请求(比如不同 Host、不同路径、甚至不同证书状态),就可能造成:
- 对未启用 HTTPS 的子域错误施加 HSTS,导致整个子域不可访问
- 缓存了过期或错误的 max-age,使策略失效或无法撤回
- 同一缓存键下多个域名共享响应时,HSTS 头被错误继承(如多租户环境)
- CDN 回源失败返回 502 时,若缓存了旧响应,HSTS 头可能丢失,安全通道中断
确保 HSTS 始终由源站生成且透传到边缘
正确做法是让 CDN 只做“透明代理”,不缓存 HSTS 头本身,而是保证它从源站原样传递:
- 在 Nginx 的 443 server 块中添加:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - 确认 CDN 控制台开启“自定义响应头透传”(Cloudflare 叫 Edge Cache TTL → Custom Cache Key → Include Response Headers;腾讯云 EdgeOne 需勾选 透传源站响应头)
- 禁用 CDN 对
Strict-Transport-Security的任何自动注入或覆盖逻辑(部分 CDN 默认屏蔽该头)
规避越权污染的关键控制点
HSTS 污染通常源于跨租户、跨域名或跨证书状态的响应混用。需从三方面隔离:
-
缓存键必须包含证书标识或 server_name:避免不同域名共用同一缓存实体。例如在 Nginx 中配置:
proxy_cache_key "$scheme$request_method$host$ssl_server_name$request_uri"; - 禁止对 301/302 跳转响应缓存 HSTS:跳转页(如 HTTP→HTTPS)本身不该带 HSTS,只应在最终 HTTPS 页面响应中下发
-
子域策略分治:若 api.example.com 和 blog.example.com 使用不同证书或运维团队,不要共用
includeSubDomains;改用独立 server 块分别配置 HSTS,且 CDN 缓存键中加入$host确保隔离
验证是否安全透传
上线后必须逐项检查:
- 用
curl -I https://example.com查看响应头,确认 HSTS 出现在结果中,且max-age值与 Nginx 配置一致 - 对比直接访问源站和通过 CDN 访问的响应头,二者必须完全一致(尤其注意 404、500 等异常状态码下是否仍含 HSTS)
- 访问子域(如
https://api.example.com),确认其 HSTS 值独立、有效,不依赖主站缓存 - 在
chrome://net-internals/#hsts中查询域名,确认浏览器收到的是源站真实策略,而非 CDN 注入的副本











