Fetch 元数据请求标头

W3C 工作草案,

关于本文件的更多详情
此版本:
https://www.w3.org/TR/2026/WD-fetch-metadata-20260921/
最新发布版本:
https://www.w3.org/TR/fetch-metadata/
编辑器草稿:
https://w3c.github.io/webappsec-fetch-metadata/
以前的版本:
历史:
https://www.w3.org/standards/history/fetch-metadata/
反馈:
public-webappsec@w3.org 邮件主题为 “[fetch-metadata] … 消息主题 …” (档案)
GitHub
编辑:
(Google Inc.)
参与:
提交问题 (打开的问题)
测试:
web-platform-tests fetch/sec-metadata/

摘要

本文档定义了一组 Fetch 元数据请求头,旨在为服务器提供足够的信息,使其能够根据请求的方式以及其所用的上下文,事先判断是否响应该请求。

本文档状态

本节描述本文档发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版 可在 W3C 技术报告 索引中找到。

本文档由 Web 应用安全工作组 作为工作草案使用推荐标准 轨道发布。本文档旨在成为 W3C 推荐标准。

(已归档的)公共邮件列表 public-webappsec@w3.org (参见说明) 是讨论本规范的首选方式。 发送电子邮件时, 请在主题中加入文本“fetch-metadata”, 最好采用如下格式: “[fetch-metadata] ……评论摘要……”

作为工作草案发布并不意味着 W3C 及其成员认可本文档。本文档为草案,可能随时被 其他文档更新、替代或 废止。不应以进行中的工作以外的方式引用 本文档。

本文档由 Web 应用安全工作组制作。

本文档由一个依照 W3C 专利政策运作的小组制作。 W3C 维护一份与该小组交付成果相关的所有 专利披露的公开列表; 该页面还包含披露专利的说明。 如果某人确切知晓一项其认为包含必要权利要求的专利, 则必须按照W3C 专利政策第 6 节披露相关信息。

本文档受2025 年 8 月 18 日 W3C 流程文档管辖。

1. 简介

有趣的网页应用通常会有大量对外暴露的端点,这些端点可能暴露用户的敏感数据,或以用户身份执行某些操作。由于用户的浏览器很容易被诱导去访问这些端点,并在请求中带上用户现有的凭据(如 cookies、内网特权身份等),因此应用程序在设计这些端点时必须非常谨慎,以防止滥用。

在某些情况下做到谨慎非常困难(如“简单”的CSRF),而在另一些情况(如跨站搜索、计时攻击等)几乎不可能。后一类问题包括基于服务器生成特定响应时的处理时长的计时攻击,以及基于响应长度的各种攻击(包括面向Web的计时攻击和被动网络攻击者)。

如果服务器能够根据请求的方式更智能地决定是否响应,将有助于缓解后一类问题。例如,一个银行服务器上的“转出我所有资金”的端点几乎不可能被放在 img 标签中引用,同样,evil.com 发起任何合法请求的概率也非常低。理想情况下,服务器可以事先拒绝这些请求,而不是将其送到应用后端处理。

在这里,我们介绍了一种机制,用户代理可通过为外发请求添加更多上下文,实现上述决策。通过在一组Fetch 元数据请求头中向服务器传递元数据,应用可以基于若干前置条件快速拒绝请求。这项工作甚至可以提升到应用层之上(如反向代理、CDN等)来完成。

1.1. 示例

一个由 picture 元素生成的请求,会包含如下HTTP请求头:

Sec-Fetch-Dest: image
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site

如果用户点击页面内的链接,从 https://example.com 跳转到 https://example.com/,则会生成包含如下HTTP请求头的请求:

Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1

2. Fetch 元数据请求头

下文定义了多个Fetch 元数据请求头,每个都将某个有意义的请求属性暴露给服务器。

2.1. Sec-Fetch-Dest HTTP请求头

Sec-Fetch-Dest HTTP 请求头会将请求的目标类型暴露给服务器。它是一个结构化字段,其值必须为标记(token)。[RFC9651] 其ABNF如下:

Sec-Fetch-Dest = sf-token

Sec-Fetch-Dest 的有效值包括 请求在 Fetch标准中定义的所有目标类型。

为了支持尚未定义的未来请求类型,若遇到无效值,服务器应忽略此头。

// fetch() 的 destination 为空字符串:
Sec-Fetch-Dest: empty

// <img> 的 destination 为 "image"
Sec-Fetch-Dest: image

// new Worker() 的 destination 为 "worker"
Sec-Fetch-Dest: worker

// 顶层导航的 destination 为 "document"
Sec-Fetch-Dest: document

// <iframe> 导航的 destination 为 "iframe"
Sec-Fetch-Dest: iframe
要为请求 r设置 Sec-Fetch-Dest 标头:
  1. 断言:r 的当前 URL 是一个潜在可信 URL。

  2. 令 header 为一个结构化字段,其值为一个令牌。

  3. 如果 r 的目标为空字符串,则将 header 的值设置为字符串 "empty"。否则,将 header 的值设置为 r 的目标。

    注: 我们将 Fetch 的空字符串目标映射为一个显式的 "empty" 令牌,以简化处理。

  4. 在 r 的标头列表中设置结构化字段值 `Sec-Fetch-Dest`/header。

2.2. Sec-Fetch-Mode HTTP请求头

Sec-Fetch-Mode HTTP 请求标头向服务器公开请求的 模式。它是一个结构化字段,其值必须为一个 令牌。[RFC9651] 其 ABNF 为:

Sec-Fetch-Mode = sf-token

有效的 Sec-Fetch-Mode 值包括 "cors"、"navigate"、 "no-cors"、"same-origin", 以及 "websocket"。为了支持与尚未知晓的请求类型向前兼容, 如果此标头包含无效值,服务器应忽略此标头。

要设置 Sec-Fetch-Mode 标头,对于一个请求 r:
  1. 断言:r 的当前 URL 是一个潜在可信 URL。

  2. 令 header 为一个结构化字段,其值为一个令牌。

  3. 将 header 的值设置为 r 的模式。

  4. 在 r 的标头列表中设置结构化字段值 `Sec-Fetch-Mode`/header。

2.3. Sec-Fetch-Site HTTP请求头

Sec-Fetch-Site HTTP 请求标头公开了 请求发起者的源与其目标的源之间的关系。它是一个结构化字段, 其值为一个令牌。[RFC9651] 其 ABNF 为:

Sec-Fetch-Site = sf-token

有效的 Sec-Fetch-Site 值包括 "cross-site"、"same-origin"、 "same-site" 和 "none"。 为了支持与尚未知晓的请求类型向前兼容,如果此标头包含无效值,服务器应忽略 此标头。

要为请求 r设置 Sec-Fetch-Site 标头:
  1. 断言:r 的当前 URL 是一个潜在可信 URL。

  2. 令 header 为一个结构化字段,其值为一个令牌。

  3. 将 header 的值设置为 same-origin。

  4. 如果 r 是一个由用户与 用户代理的交互显式引起的导航请求(例如,直接在用户代理中输入地址,或 点击书签等),则将 header 的值设置为 none。

    注: 有关这个定义得不太明确的步骤的更多细节, 请参阅§ 4.3 直接由用户发起的请求。

  5. 如果 header 的值不是 none,则对于 r 的URL 列表中的每个 url:

    1. 如果 url 与 r 的源同源,则继续。

    2. 将 header 的值设置为 cross-site。

    3. 如果 r 的源与 url 的源不是同站点,则中断。

    4. 将 header 的值设置为 same-site。

  6. 在 r 的标头列表中设置结构化字段值 `Sec-Fetch-Site`/header。

2.4. Sec-Fetch-User HTTP请求头

Sec-Fetch-User HTTP 请求标头公开了 导航请求是否由用户激活触发。它是一个结构化字段,其 值为一个布尔值。[RFC9651] 其 ABNF 为:

Sec-Fetch-User = sf-boolean

注: 此标头仅随导航请求传递,并且仅当其值为 true 时传递。 如果我们能够明确说明一些通过公开该信息而得到改善的用例 (并且如果我们能够就如何为所有我们感兴趣的子资源请求类型定义该状态达成一致), 那么将来将这些标头的适用范围扩展为普遍包含子资源请求或许是合理的, 但就目前而言,导航请求有明确的用例,并且似乎 可以直接以可互操作的方式定义。

要为请求 r设置 Sec-Fetch-User 标头:
  1. 断言:r 的当前 URL 是一个潜在可信 URL。

  2. 如果 r 不是导航请求,或者 r 的用户激活为 false,则返回。

  3. 令 header 为一个结构化字段,其值为一个令牌。

  4. 将 header 的值设置为 true。

  5. 设置结构化字段值 `Sec-Fetch-User`/header 到 r 的标头列表中。

3. 与 Fetch 和 HTML 的集成

为了支持 Sec-Fetch-User,请求具有一个用户激活,其值为 false, 除非由 HTML 的通过 fetch 创建导航参数算法另行填充。

Fetch 元数据标头会在 Fetch 的“HTTP-network-or-cache” 算法中附加到传出的请求,使用以下步骤。有关集成细节,请参阅该规范[FETCH]。

要为请求附加 Fetch 元数据标头,给定请求 r:
  1. 如果 r 的当前 URL不是潜在可信 URL,则返回。

  2. 为 r设置 Sec-Fetch-Dest 标头。

  3. 为 r设置 Sec-Fetch-Mode 标头。

  4. 为 r设置 Sec-Fetch-Site 标头。

  5. 为 r设置 Sec-Fetch-User 标头。

4. 安全与隐私注意事项

4.1. 重定向

用户代理将随重定向链中的每个 请求一起发送 Sec-Fetch-Site 标头。 在存在跨源或跨站点 重定向时,该标头的值将发生变化,以减少混淆。

设置 Sec-Fetch-Site 标头的算法会遍历请求的整个 URL 列表,如果列表中的任何 URL 与 请求的当前 URL跨站点,则发送 cross-site;仅当列表中的所有 URL 与请求的当前 URL同站点时,才发送 same-site;仅当列表中的所有 URL 与请求的当前 URL同源时,才发送 same-origin。

例如,如果 https://example.com/ 请求 https://example.com/redirect,则 初始 请求的 Sec-Fetch-Site 值将为 same-origin。如果该响应重定向 到 https://subdomain.example.com/redirect,则该请求的 Sec-Fetch-Site 值将 为 same-site(因为 https://subdomain.example.com/ 和 https://example.com/ 具有相同的 可注册域)。如果该响应重定向到 https://example.net/redirect,则该 请求的 Sec-Fetch-Site 值将为 cross-site(因为 https://example.net/ 与 https://example.com/ 和 https://subdomain.example.com/ 不同站点)。如果该 响应 一路重定向回 https://example.com/,则最终请求的 Sec-Fetch-Site 值仍将为 cross-site(因为重定向链中包含 https://example.net/,它 仍然与其他 URL 不同站点。

注: 对于 Sec-Fetch-Site: None 这一特殊情况,为了支持将短链接复制/粘贴到地址 栏这一常见情形,在重定向过程中保持该值似乎是合理的。也就是说,如果用户代理选择将地址栏导航到 https://sho.rt/link 视为 Sec-Fetch-Site: none,那么重定向后的导航到 https://target.com/long/path/goes/here 同样应断言 Sec-Fetch-Site: none。

4.2. Sec- 前缀

本文档中定义的每个标头都以 Sec- 为前缀,这使它们全部成为 禁止的响应标头名称,因此 无法通过 JavaScript 修改。这将防止 恶意网站诱使用户代理随请求发送伪造的元数据, 从而应能让站点更有信心根据 所声明的信息作出合理响应。

4.3. 用户直接发起的请求

在设置 Sec-Fetch-Site 标头时,要求用户代理 区分“由用户交互显式引起”的导航请求。这个 定义得不太明确的短语取自 HTML,其中 提出 “除了本规范中定义的方式之外,用户代理还可以提供各种方式,让用户显式地使浏览上下文 导航。”

其目标是区分由给定的(可能具有 恶意意图的!)网站控制的“Web 式”导航(例如链接、window.location setter、表单提交等),以及那些 不受网站控制的导航(例如用户与用户代理的地址栏、书签等进行的交互)。前者 将随一个 Sec-Fetch-Site 标头一起传递,其值根据情况为 same-origin、 same-site 或 cross-site。后者将通过值 none 加以区分, 因为实际上并没有 特定站点对该请求负责,并且允许服务器将 这些请求视为可信请求是合理的,因为它们以某种方式代表了用户的直接意图。

每个用户代理可能都有一组不同的交互方式,这些交互可能属于其中一个或另一个 类别,并且很难为这些情况共享自动化测试套件。不过, 最好还是能在那些可能比较常见的行为上保持一致。下面是一些示例:

4.4. 扩展发起的请求

一些用户代理支持能够发出请求的扩展,并且这些扩展可以被赋予 超出普通 Web 内容的能力,以便让用户更好地控制其 Web 使用体验。虽然这些扩展 在某种程度上超出了 Web 平台的范围,但仍鼓励用户代理仔细考虑 应如何向服务器表示这些请求。一般而言,用户代理最好能够 满足以下两个目标:

  1. 对于给定站点不具有特殊权限的扩展,不能发出会绕过 该站点服务器端 Fetch 元数据逻辑的请求。

  2. 开发者能够识别扩展发出的请求,从而在服务器选择这样做时,可以将这些请求排除在其 Fetch 元数据逻辑之外。这增强了开发者有信心部署 Fetch 元数据保护措施的能力,同时不会损害用户的合法利益。

基于这些目标,鼓励用户代理实现以下行为:

  1. 如果扩展无权访问给定 URL,则它向该 URL 发出的请求可以 包含一个值为 cross-site 的 Sec-Fetch-Site 标头,就像 普通 Web 请求一样。 如果扩展确实有权访问给定 URL,则 Sec-Fetch-Site 的值可以为 same-origin。

  2. 从扩展上下文发出的传出请求中可以包含 Origin 标头,其 由实现定义的值应允许服务器 区分由扩展发起的请求 与由 Web 发起的请求。

5. 部署注意事项

5.1. Vary

如果给定端点的响应取决于客户端在 Fetch 元数据 标头中提供的值,则开发者应谨慎地包含适当的 Vary 标头 [RFC9110],以确保 缓存能够正确处理该响应。例如, Vary: Accept-Encoding, Sec-Fetch-Site。

5.2. 头部冗余

本文档的早期版本定义了单个 Sec-Metadata 标头,其内容为 一个字典。后续讨论(以及 Mark Nottingham 出色的 [mnot-designing-headers])将设计从 单个字典转变为一系列简单的 标头,每个标头仅包含单个令牌。采用这种设计后,在 HTTP 当前的 HPACK 压缩算法下,其性能应显著更好。

有关该主题的进一步讨论可参见以下评审线程: w3ctag/design-reviews#280。

6. IANA 注意事项

永久消息标头字段注册表应更新,以加入以下 Fetch 元数据 标头注册项:[RFC3864]

6.1. Sec-Fetch-Dest 登记

头字段名称

Sec-Fetch-Dest

适用协议

http

状态

standard

作者/变更控制者

Me

规范文档

本规范(参见 § 2.1 Sec-Fetch-Dest HTTP 请求头)

6.2. Sec-Fetch-Mode 登记

头字段名称

Sec-Fetch-Mode

适用协议

http

状态

standard

作者/变更控制者

Me

规范文档

本规范(参见 § 2.2 Sec-Fetch-Mode HTTP 请求头)

6.3. Sec-Fetch-Site 登记

头字段名称

Sec-Fetch-Site

适用协议

http

状态

standard

作者/变更控制者

Me

规范文档

本规范(参见 § 2.3 Sec-Fetch-Site HTTP 请求头)

6.4. Sec-Fetch-User 登记

头字段名称

Sec-Fetch-User

适用协议

http

状态

standard

作者/变更控制者

Me

规范文档

本规范(参见 § 2.4 Sec-Fetch-User HTTP 请求头)

7. 致谢

感谢 Anne van Kesteren、Artur Janc、Dan Veditz、Łukasz Anforowicz、Mark Nottingham 和 Roberto Clapis,他们为该机制设计提供了大量支持。

一致性要求

文档约定

一致性要求以描述性断言和 RFC 2119 术语的结合方式表达。 规范性部分出现的 “MUST”(必须)、“MUST NOT”(禁止)、“REQUIRED”(必要)、“SHALL”(应)、 “SHALL NOT”(不得)、“SHOULD”(应当)、“SHOULD NOT”(不应)、“RECOMMENDED”(推荐)、“MAY”(可以) 和 “OPTIONAL”(可选),应按照 RFC 2119 的定义解释。但为了可读性,本规范中这些词不会全部大写。

除非特别标注为非规范性、示例和注释,否则本规范所有文本均为规范内容。[RFC2119]

本规范中的示例以 “for example” 开头,或用 class="example" 与规范文本区分,例如:

这是一个说明性示例。

说明性注释以“Note”开头,并用 class="note" 附加于规范性文本,例如:

注,这是一个说明性注释。

一致性算法

以祈使语气表达的算法要求(如“去掉任何前导空格”或“返回 false 并终止这些步骤”)应按照引入该算法时所用的关键字(例如 “must”/“should”/“may” 等)予以解释。

以算法或特定步骤表述的一致性要求,只要最终效果等价,实现方式可以多样。本规范中的算法旨在易于理解,而非追求性能极致。鼓励实现方自行优化。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[FETCH]
Anne van Kesteren. Fetch 标准。现行 标准。URL:https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准。 现行标准。URL:https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准。现行标准。URL:https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. 用于 RFC 中 指示要求级别的关键词。1997 年 3 月。最佳当前实践。URL:https://datatracker.ietf.org/doc/html/rfc2119
[RFC3864]
G. Klyne; M. Nottingham; J. Mogul. 消息标头字段的注册 程序。2004 年 9 月。最佳当前实践。URL:https://www.rfc-editor.org/info/rfc3864/
[RFC9651]
M. Nottingham; P-H. Kamp. HTTP 的结构化字段值 。2024 年 9 月。提议标准。URL:https://www.rfc-editor.org/info/rfc9651/
[SECURE-CONTEXTS]
Mike West. 安全上下文。2023 年 11 月 10 日。CRD。URL:https://www.w3.org/TR/secure-contexts/
[URL]
Anne van Kesteren. URL 标准。现行标准。 URL:https://url.spec.whatwg.org/

参考性引用

[MNOT-DESIGNING-HEADERS]
Mark Nottingham. 设计用于HTTP压缩的头字段. URL: https://www.mnot.net/blog/2018/11/27/header_compression
[RFC9110]
R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. HTTP语义. 2022年6月. Internet Standard. URL: https://httpwg.org/specs/rfc9110.html
✔MDN

Headers/Sec-Fetch-Dest

In all current engines.

Firefox90+Safari16.4+Chrome80+
Opera?Edge80+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera MobileNone
✔MDN

Headers/Sec-Fetch-Mode

In all current engines.

Firefox90+Safari16.4+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Headers/Sec-Fetch-Site

In all current engines.

Firefox90+Safari16.4+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

Headers/Sec-Fetch-User

In all current engines.

Firefox90+Safari16.4+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?