OpenResty/Nginx:HSTS(Strict-Transport-Security)响应头排查与治理指南
适用场景
当站点已删除 vhost 中的 HSTS 配置,但客户端仍持续收到:
Strict-Transport-Security: max-age=31536000
并表现为“浏览器持续强制 HTTPS”或“清理 HSTS 后再次访问又被重新写入”。
本文给出一套可复用的排查与治理流程,适用于 OpenResty/Nginx 反向代理与非反向代理两类站点。
现象确认(以响应头为准)
优先用命令确认是否仍在下发 HSTS:
curl -kI https://192.168.xxx.xxx:443/ | sed -n '1,40p'
若输出包含:
strict-transport-security: max-age=31536000
则可确定:HSTS 来源在服务端链路中(并非浏览器“自动开启”)。
背景机制(为何“删掉一处配置”仍可能存在)
- HSTS 仅在 HTTPS 响应中生效;浏览器一旦接收到该头,会按
max-age缓存。 - HSTS 以 Host 为维度缓存(不是以端口为维度)。
- 站点层删除 HSTS 配置,不等价于整条链路不再下发该头:
- 可能存在 include 模板配置
- 可能存在 Nginx/OpenResty 全局
http {}配置 - 可能来自上游应用响应头,并被代理层透传
常见来源与定位顺序
1) include 进来的站点模板(高概率)
典型表现:vhost 中存在类似:
include /www/sites/xxx/proxy/*.conf;
某个被 include 的文件中仍配置:
add_header Strict-Transport-Security "max-age=31536000" always;
2) OpenResty/Nginx 全局层面(http{})统一加固
某些面板/模板会在全局启用 HSTS,使所有站点都带该头。
3) 上游应用自行返回 HSTS
当 OpenResty/Nginx 作为反向代理时,上游应用可能直接返回 HSTS。
若代理层未主动处理,该头会被原样转发给客户端。
根治方案(推荐):从“实际生效配置”定位源头
在服务器上展开最终生效配置并搜索关键字:
openresty -T 2>&1 | grep -in "strict-transport-security"
若使用 nginx:
nginx -T 2>&1 | grep -in "strict-transport-security"
命令输出会给出“文件路径 + 行号”,据此删除或调整对应的 add_header Strict-Transport-Security ...,再 reload。
说明:该方法用于定位 OpenResty/Nginx 配置侧的来源。若输出为空,但响应仍有 HSTS,则更可能来自上游应用响应头。
治理方案(站点层可控):屏蔽上游并清理客户端历史 HSTS
当无法立即修改全局模板、或不确定上游是否会继续下发 HSTS 时,可在站点层做“控制权收敛”,确保最终由 OpenResty 决定是否开启 HSTS。
建议配置:
proxy_hide_header Strict-Transport-Security;
add_header Strict-Transport-Security "max-age=0" always;
配置含义
proxy_hide_header Strict-Transport-Security;- 屏蔽上游应用返回的 HSTS 响应头,避免上游影响客户端策略。
add_header Strict-Transport-Security "max-age=0" always;- 通过 HTTPS 响应向客户端下发“清理指令”,将该 host 的 HSTS 记录清空;
always确保 4xx/5xx 等响应也携带该头。
- 通过 HTTPS 响应向客户端下发“清理指令”,将该 host 的 HSTS 记录清空;
放置位置(关键)
- 若站点存在
proxy_pass(反向代理):proxy_hide_header应放在发生反代的location作用域内,或确保可覆盖到所有反代location。
- 若站点为纯静态/直出:
proxy_hide_header无意义,可仅保留add_header ... max-age=0 always;用于清理客户端历史记录。
验证步骤
1) 服务端验证
再次查看响应头:
curl -kI https://192.168.xxx.xxx:443/ | sed -n '1,40p'
期望:
- 不再出现
strict-transport-security - 或仅出现
strict-transport-security: max-age=0
2) 客户端验证
若客户端此前已缓存 HSTS(max-age 较大),建议删除浏览器侧记录后复测:
- Chrome/Edge:
chrome://net-internals/#hsts删除对应 host(示例:192.168.xxx.xxx)
注意事项
- 关闭 HSTS 会降低安全性。对公网站点,需评估是否允许降级攻击风险。
- 某些环境下
error_page 497 https://$host$request_uri;会导致“HTTP 误打到 SSL 端口时自动跳转 HTTPS”,其表现可能与 HSTS 类似,但原理不同。 - 若 OpenResty 前还有更外层的网关/CDN/WAF 且其追加 HSTS,OpenResty 无法删除“外层后来添加”的响应头,需要在外层关闭。
回滚与启用策略
- 如需重新启用 HSTS:
- 删除
max-age=0清理策略 - 在期望层级(站点或全局)配置目标策略(例如
max-age=31536000) - 使用
curl -kI复核响应头
- 删除