HSTS必须在首次HTTPS响应中发送,否则浏览器无法记录策略;若仅在HTTPS server块内配置,HTTP跳转的301响应不带HSTS头,导致首次生效失败,故需在全局配置中用Header always set确保所有HTTPS响应(含重定向)均携带该头。

为什么 Header always set Strict-Transport-Security 必须放在全局配置最外层
因为 HSTS 必须在首次响应(包括重定向前的 301/302)中生效,否则浏览器不会记住该策略。如果只写在某个 <virtualhost></virtualhost> 块里,而用户直接访问 HTTP 版本(如 http://example.com),Apache 先返回 301 跳转到 HTTPS,这个跳转响应本身不带 Strict-Transport-Security —— 就算后续 HTTPS 响应加了,也已错过首次机会。
正确做法是把 Header always set Strict-Transport-Security 放在 httpd.conf 底部或 /etc/httpd/conf.d/security-headers.conf 中,且确保它位于所有 <virtualhost></virtualhost> 块之外。同时验证 mod_headers 已启用:a2enmod headers(Debian/Ubuntu)或确认 LoadModule headers_module modules/mod_headers.so 在主配置中未被注释。
如何用条件判断只对 HTTPS 域名启用 HSTS preload
preload 不是开关,而是向浏览器预加载列表提交的承诺:一旦启用,撤回需数月,且必须满足全站 HTTPS、includeSubDomains、至少 max-age=31536000 等硬性条件。盲目全局加 preload 可能导致子域名临时 HTTP 维护时整个站点不可访问。
推荐按域名条件启用:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 用
<if></if>包裹Header always set指令(Apache 2.4.10+ 支持) - 或拆分配置:为生产环境单独建
prod-security.conf,仅 Include 到对应<virtualhost></virtualhost> - 绝对避免在开发/测试域名(如
staging.example.net)中出现preload字样
为什么 CSP 不能简单 global set,而要配合 unset + set 分层覆盖
全局 Header always set Content-Security-Policy 会污染所有响应,包括 API 接口(JSON)、静态资源(CSS/JS)、甚至错误页(404/500)。例如:
- API 返回
application/json却被套上script-src 'self',虽不影响解析,但违反语义且干扰安全扫描 - 某子站需嵌入第三方地图 iframe,但全局
frame-ancestors 'none'直接封死 - 虚拟主机内用
Header set试图覆盖,结果两个 CSP 头并存,浏览器取第一个,旧值仍生效
正确流程是:在虚拟主机内先 Header unset Content-Security-Policy,再 Header always set 新策略。若需差异化,可结合 <filesmatch></filesmatch> 或 <location></location> 做路径级控制。
常见踩坑:X-XSS-Protection 和 CSP 的冲突逻辑
现代浏览器(Chrome 78+、Firefox 76+)已废弃 X-XSS-Protection,且当 CSP 存在 script-src 时,该头会被忽略。但留着它仍有风险:
-
X-XSS-Protection: 1; mode=block在旧版 IE/Edge 中可能误拦截合法内联脚本,导致白屏 - 若 CSP 放宽了
script-src 'unsafe-inline',而X-XSS-Protection又开启,两者行为矛盾,调试困难 - 权威建议是显式关闭:
Header always set X-XSS-Protection "0",而非删掉——避免某些中间件自动注入
真正起效的是 CSP 的 script-src 和 nonce/hash 机制,其他头只是辅助或兼容层。别让过时的防御逻辑掩盖真实策略缺陷。

















