Back to articles

大多数网站仍然忽略的安全头:来自 49 实际审计的数据

SEOReport Team·
security-headersweb-securitycsphststechnical-seoseo-audit

响应头是随任何部署一起发送的单行配置。在我们审计的站点中,大多数都没有发送它们——Permissions-Policy 在 69% 上缺失,列表中最常用的头仍在 41% 上缺失.

我们运行的每次审计都会读取主页的响应头. 6 其中之一给出通过或失败的判定;report-only CSP 和跨源隔离对仅用于上下文报告,且永不计为失败. 读取发生在普通 HTTP fetch 上——与 AI 爬虫接收的捕获相同——以及重定向后的最终响应上,因此仅在预重定向跳点设置头部的站点不会获得任何信用。 引擎询问的问题故意狭窄:响应是否携带该头部. 在 49 个在 23 至 August 31, 2026 之间审计的站点中,答案通常是否定的. Permissions-Policy 在其中 69% 缺失,Referrer-Policy 在 65% 缺失,Content-Security-Policy 在 61% 缺失,X-Frame-Options 在 51% 缺失,X-Content-Type-Options 在 43% 缺失,Strict-Transport-Security——最常用的 6——在 41% 缺失. 方法论:每个域名的最新完成审计快照来自我们当前的检查集,约为 23 5 月至 August 31, 2026,共 49 个不同域名,已匿名化。 每个百分比表示主页响应未携带该头部的站点比例。 样本为自选——已运行审计的所有者——倾向于小型和中型站点,可能低估了整个网络的头部采用率,因为大型平台在边缘设置这些头部。 将这些比例视为长尾的方向性指标。

Share of 49 Audited Sites Missing Each Security Header

检查询问头部是否存在,而非其是否良好

对测量的精确性很重要,因为它决定了这些数字能声称的上限. 引擎仅读取主页——一次 URL,一次响应——并在可用时从普通-HTTP 捕获中获取头部值,若不可用则回退到其他主页捕获。 存在意味着非空值. 没有指令的评分:Strict-Transport-Securitymax-age 为 1 秒即通过,Content-Security-Policy 允许任何内容也同样通过。 通过判定并不说明策略构造良好. 这看起来像一个弱指标,直到你考虑它衡量的内容. 任何值的头部都是人类曾经打开服务器配置、CDN 规则或中间件文件并输入指令的证据。 检查是测试站点配置层是否曾被有意触碰——这就是失败率为何有趣,而非通过率. 严重性按头部分配,而非统一. Strict-Transport-Security 和 Content-Security-Policy 在高严重性下失败. X-Frame-Options、X-Content-Type-Options、Referrer-Policy 和 Permissions-Policy 在中等强度下失败. Cross-origin isolation、COOP 和 COEP 对,只有信息性——当任一头部存在时通过,否则仅报告信息性裁决,永不失败,因为这些头部控制的是高级浏览器功能,而非基础防御. 在阅读自己的报告之前,值得了解的两点行为:

  • Report-only CSP 不满足 CSP 检查。 引擎会特别查看 Content-Security-Policy。 仅运行 Content-Security-Policy-Report-Only 的站点会通过执行检查并收到单独的信息性裁决,说明违规已被记录但未被阻止。 该裁决仅在两种 CSP 头部之一存在时出现.
  • frame-ancestors 不满足 X-Frame-Options 检查。 引擎会自行读取 X-Frame-Options 头部。 现代 CSP 配合 frame-ancestors 指令是更好的控制方式,而在移除旧头部的同时提供它的站点仍会看到该检查失败。

代码中还有一个平台适配。当响应来自 Vercel 并且页面加载 Vercel 的 BotID 脚本时,缺失 CSP 仍会失败,但强度为中等而非高,并附有说明 BotID 需要内联脚本许可以对抗严格 CSP 执行的注释。站点可以通过在首页前 1 KB 内放置一个 HTML 注释,例如 <!-- seoreport-ignore: vercel-botid-csp -->,来有意记录此约束;当原因是 CSP 或 BotID 时,检查会降为信息性裁决而非失败。这是该系列中唯一的逃逸口,并且存在是因为真实平台约束不应被视为疏忽。

采用情况跟踪的是头部的年龄,而非其难度

失败率的排序接近逆时间顺序。HSTS 是 6 个中最旧的,并可在每个主要 CDN 仪表盘中切换,是采用最广泛的。 X-Content-Type-Options 和 X-Frame-Options,都是在正式后继者出现之前就已存在的供应商约定,位于中间位置. Referrer-Policy 和 Permissions-Policy,两个最新的,缺失率最高——而 Permissions-Policy,常见主机不会为你设置,排在最后. 它们在工程层面上没有一个比其他更难. 6 个中的 5 个只需在服务器块、CDN 规则或边缘中间件文件中添加一行静态指令,无需应用更改,也无行为风险。 区分它们的是它们积累默认值的时间长短,以及有多少博客文章、检查清单和框架模板已吸收它们. 我们在 对我们审计历史中所有失败检查进行排名 时看到相同的模式:响应头占据列表顶部,位于规范化、渲染和性能之上. 那个排名覆盖了不同窗口、不同样本和更早的检查集,因此两组百分比并非趋势线——但两者顶部头部的位置是持久发现. 另一结构原因是不可见性. 缺失头部在屏幕上不产生任何变化. CMS 不会警告你,构建不会失败,仪表盘也不会变红. 缺失仅对检查原始响应的工具可见——这正是审计、浏览器安全状态以及越来越多自动化阅读器所做的. 这与我们在 渲染一致性 中发现的相同不对称性相同:人类在浏览器中看到的与机器通过 HTTP 接收的内容悄然分离。

每个头部的保护作用

Strict-Transport-Security 告诉浏览器在指定期间拒绝对你域的明文 HTTP,从而关闭攻击者在网络上劫持重定向窗口,直至你的 http://https:// 重定向生效。 它也是列表中唯一带有承诺的头部:浏览器会遵守 max-age,即使你随后破坏 HTTPS。先简短,确认每个子域和资源都能通过 TLS 干净地提供,然后再扩展。

Strict-Transport-Security: max-age=31536000; includeSubDomains

Content-Security-Policy 限制脚本、样式、框架和连接的来源. 它是这里唯一包含事件而非阻止某类事件的头部:当标签管理器被破坏或用户输入到达 DOM 时,CSP 决定注入的脚本是否能执行或到达它选择的服务器. 它也是唯一能破坏正常页面的头部,这就是为什么它放在下面序列的末尾.

Content-Security-Policy-Report-Only: default-src 'self'

X-Frame-Options 声明其他来源是否可以将你的页面放入框架. 没有它,你的界面可能会被嵌入到攻击者页面的透明覆盖层下,并被相信自己在你站点上的用户点击. 现代 CSP 用 frame-ancestors 表达得更好;同时发布两者,因为旧版头部是旧客户端和我们自己的检查所读取的。

X-Frame-Options: DENY

X-Content-Type-Options 阻止浏览器在声明的 Content-Type 看起来错误时猜测响应类型。 通过嗅探,上传的文件被当作文本提供时可能会被执行为脚本. 该头部恰好有 1 个有效值.

X-Content-Type-Options: nosniff

Referrer-Policy 管理当前 URL 的多少会随外部点击和子资源加载传递给第三方。 你的 URL 带有活动参数、内部搜索查询、账户标识符,有时还有令牌,页面上每个分析像素和字体 CDN 都是接收者。 主流浏览器已趋向合理默认值,但默认值是用户代理为你做出的决定,且因客户端而异;发送该头部使你的策略明确,并允许处理敏感 URL 的站点选择更严格的策略,例如 same-origin

Referrer-Policy: strict-origin-when-cross-origin

Permissions-Policy 决定你的文档及其嵌入框架可以请求哪些浏览器功能——摄像头、麦克风、地理位置,以及其他强大功能列表. 缺少该头部,所有未被禁用的功能都对页面上的每个脚本可用,包括你未编写的第三方标签. 拒绝你不使用的功能.

Permissions-Policy: camera=(), microphone=(), geolocation=()

先发布 4 单行指令,然后花一个下午处理 CSP

引擎严重性和部署风险在确切的 1 头部上存在分歧,修复顺序将分歧倾向于发布.

graph TD A[阅读你自己的响应头] --> B[部署 1:HSTS,短 max-age] B --> C[部署 2:nosniff、Referrer-Policy、Permissions-Policy、X-Frame-Options] C --> D[在 TLS 在所有地方确认后扩展 HSTS max-age] D --> E[CSP 在仅报告模式下] E --> F{违规报告干净?} F -->|否| G[调整源,保持仅报告] G --> F F -->|是| H[强制 CSP,添加 frame-ancestors]

部署 1 — HSTS,简短。 最高严重性,且当你的网站已在所有地方提供 HTTPS 时,风险几乎为零。 先设置一个适度的 max-age,以便在被遗忘的子域出现 TLS 问题时仍可恢复。 部署 2 — 将 4 条中等严重性行一起部署。 nosniff, Referrer-Policy, Permissions-PolicyX-Frame-Options 是静态值,没有应用依赖。 它们是 4 的 6 检查,并且在这些失败率下,平均网站缺失的大部分内容. 没有理由单独分阶段它们. 然后扩展 HSTS, 一旦你确认域下的每个主机都能通过 TLS 干净地提供服务. 最后 — CSP,在仅报告模式。 部署 Content-Security-Policy-Report-Only,收集真实流量的违规,并枚举你实际依赖的脚本和连接来源。 只有在此之后才将头部切换为强制,并在你的 X-Frame-Options 行旁添加 frame-ancestors。 最高严重性,最高努力,序列中的最后一步,因为它是列表中唯一能让工作页面崩溃的项目.

在 1 命令中读取你自己的头部

整个测量可从终端重现。跟随重定向,因为引擎就是这么做的:

bash
curl -sSL -o /dev/null -D - https://example.com/ \
| grep -iE 'strict-transport-security|content-security-policy|x-frame-options|x-content-type-options|referrer-policy|permissions-policy'

每一行未返回即是检查你的主页失败. 所有 6 返回意味着存在栏已清除,接下来的问题——政策本身是否有价值——值得提出. 我们的 免费报告 在每次审核时执行相同的读取,并列出每个缺失头部及其解决值。 该数据集中的头部并非因难以获取或有争议而缺失. 它们缺失是因为网站日常运作中从未出现其缺失:没有错误、没有视觉变化、没有构建失败. 通过的站点是那些曾有人去寻找的——而那一次部署仍对大多数未找到的用户可用.

查看您的网站排名

获取一份免费的 AI 驱动的 SEO 报告,包含可操作的发现和优先修复建议,帮助提升您的网站。

不需要注册。.