获取元数据请求头

W3C 工作草案

关于本文件的更多详情
此版本:
https://www.w3.org/TR/2025/WD-fetch-metadata-20250401/
最新发布版本:
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 技术报告索引 https://www.w3.org/TR/。

本文档由 Web 应用安全工作组 作为工作草案,根据 推荐流程 发布。本文件计划成为 W3C 推荐标准。

(存档) 公开邮件列表 public-webappsec@w3.org (参见邮件说明) 为本规范讨论首选渠道。 发送邮件时, 请在主题中包含“fetch-metadata”, 推荐格式如下: “[fetch-metadata] …评论摘要…

作为工作草案发布并不表示 W3C 及其成员的认可。本文档为草案,可能随时更新、替换或废止。除“进行中的工作”外,不应引用本文件。

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

本文档由遵循 W3C 专利政策 的工作组编写。 W3C 维护着与本组成果相关的专利披露公开列表; 页面同时包含披露专利的说明。 若个人实际知晓并认为某专利包含必要声明,必须按W3C 专利政策第6节进行披露。

本文档受 2023年11月3日 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. 断言:rurl可能值得信任的 URL

  2. header 为一个结构化字段,其值为标记(token)

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

    注:将 Fetch 的空字符串 destination 显式映射为 "empty" token,是为了简化处理。

  4. Sec-Fetch-Dest/header设置结构化字段值,写入r请求头列表

2.2. Sec-Fetch-Mode HTTP请求头

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

Sec-Fetch-Mode = sf-token

Sec-Fetch-Mode 的有效值包括 "cors"、"navigate"、 "no-cors"、"same-origin" 和 "websocket"。为支持尚未定义的新类型请求,若遇到无效值,服务器应忽略此头。

要为请求 r设置 Sec-Fetch-Mode
  1. 断言:rurl可能值得信任的 URL

  2. header 为一个结构化字段,其值为标记(token)

  3. header 的值设为 r模式(mode)

  4. Sec-Fetch-Mode/header设置结构化字段值,写入r请求头列表

2.3. Sec-Fetch-Site HTTP请求头

Sec-Fetch-Site HTTP请求头会暴露请求的发起方与目标的来源关系。它是一个结构化字段,值为标记(token)[RFC9651] 其ABNF如下:

Sec-Fetch-Site = sf-token

Sec-Fetch-Site 的有效值包括 "cross-site"、"same-origin"、 "same-site" 和 "none"。 为支持未知的未来请求类型,遇到无效值时服务器应忽略此头。

要为请求 r设置 Sec-Fetch-Site
  1. 断言:rurl可能值得信任的 URL

  2. header 为一个结构化字段,其值为标记(token)

  3. header 的值设为 same-origin

  4. 如果 r 是一个导航请求,且明确由用户操作触发(例如,直接在用户代理输入地址,或点击书签等),则将 header 的值设为 none

    注:更详细解释见§ 4.3 用户直接发起的请求

  5. 如果 header 的值不是 none,则对 rurl 列表中的每个 url

    1. 如果 urlrorigin同源,则继续

    2. header 的值设为 cross-site

    3. 如果 roriginurlorigin 不是同站,则中断

    4. header 的值设为 same-site

  6. Sec-Fetch-Site/header设置结构化字段值,写入r请求头列表

2.4. Sec-Fetch-User HTTP请求头

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

Sec-Fetch-User = sf-boolean

注:该头仅用于导航请求,且仅在其值为 true 时传递。未来若能明确哪些场景受益,并定义所有相关子资源请求的用户激活状态,也许可以扩展到更广泛场景,但目前导航请求已经有清晰的用例并易于一致性实现。

要为请求 r设置 Sec-Fetch-User
  1. 断言:rurl可能值得信任的 URL

  2. 如果 r 不是导航请求,或 ruser-activationfalse,则返回。

  3. header 为一个结构化字段,其值为标记(token)

  4. header 的值设为 true

  5. Sec-Fetch-User/header设置结构化字段值,写入r请求头列表

3. 与 Fetch 和 HTML 的集成

为了支持 Sec-Fetch-Userrequest 拥有 user-activation,默认为 false, 除非由 HTML 的 create navigation params by fetching 算法赋值。

Fetch 元数据请求头在 Fetch 的 "HTTP-network-or-cache" 算法中被附加到外发请求,具体步骤如下。集成细节请参阅规范 [FETCH]

为请求追加 Fetch 元数据请求头,给定 request r
  1. 如果 rurl 不是 可能值得信任的 URL,则返回。

  2. 设置 Sec-Fetch-Destr

  3. 设置 Sec-Fetch-Moder

  4. 设置 Sec-Fetch-Siter

  5. 设置 Sec-Fetch-Userr

4. 安全与隐私注意事项

4.1. 重定向

用户代理会在重定向链中的每个请求上都携带 Sec-Fetch-Site 头。当出现跨源或跨站点重定向时,该头的值会随之变化以减少混淆。

用于设置 Sec-Fetch-Site的算法遍历 request 的全部 url 列表,如果列表中有任何 URL 与请求的 当前 url 跨站,则发送 cross-site;仅当所有 URL 均为同站时,值才为 same-site;仅当所有 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://example.net/redirect,新的 Sec-Fetch-Site 值为 cross-site(因其与前两个 URL 非同站)。如果后续重定向又回到 https://example.com/,由于链路中已经出现非同站 URL,最终请求的 Sec-Fetch-Site 依然是 cross-site

注:对于 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 规范,提出:“除规范明确定义之外,用户代理可为用户提供多种明确发起浏览上下文导航的方式。”

目标是区分受站点(可能为恶意)的“网页导航”(如链接跳转、window.location 赋值、表单提交等)和真正由用户意图驱动的操作(如地址栏输入、书签点击等)。前者的 Sec-Fetch-Site 头会被设置为 same-originsame-sitecross-site。后者的值则为 none,表示并无特定站点引发该请求,因此可被服务器视作可信用户行为。

不同用户代理在交互细节上可能存在实现差异,这些场景很难实现完全自动化测试。不过主流行为还是可以协调一致,以下是常见示例:

4.4. 扩展发起的请求

部分用户代理支持扩展插件发起请求,这类扩展往往拥有远超普通网页内容的能力,为用户提供更多控制 Web 的方式。虽然这一部分超出了 Web 平台的直接规范范围,但用户代理仍应仔细考虑这些请求应如何向服务器展示。总体而言,应遵循两个目标:

  1. 对于没有某站点特殊权限的扩展,不能允许其发起绕过服务端 Fetch 元数据校验的请求。

  2. 开发者可以识别扩展发起的请求,从而在必要时将其从服务端的 Fetch 元数据校验中豁免。这有利于在不影响用户正常需求的前提下安全部署该机制。

基于上述考虑,建议用户代理实现以下行为:

  1. 如果扩展对某 URL 无访问权限,则其请求的 Sec-Fetch-Site 应为 cross-site,与普通网页请求一致;若拥有该权限,则可为 same-origin

  2. 扩展上下文的请求可附带 Origin 头,值为实现自定义的特殊字符串,从而帮助服务器区分扩展发起的请求与网页发起的请求。

5. 部署注意事项

5.1. Vary

如果某端点的响应依赖于客户端提供的 Fetch 元数据头,开发者应当谨慎地在响应中包含合适的 Vary[RFC9110],确保缓存系统合理处理该响应。例如: Vary: Accept-Encoding, Sec-Fetch-Site

5.2. 头部冗余

本规范早期版本曾定义过单一 Sec-Metadata 字典型头字段。经多方讨论(包括 Mark Nottingham 的 [mnot-designing-headers]),设计转向为一组简单头字段,每个仅承载单一 token。新设计在现有 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 标准. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. 在 RFCs 中用于指明需求级别的关键词. 1997年3月. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC3864]
G. Klyne; M. Nottingham; J. Mogul. 消息头字段的注册过程. 2004年9月. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc3864
[RFC9651]
M. Nottingham; P-H. Kamp. HTTP 结构化字段值. 2024年9月. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc9651
[SECURE-CONTEXTS]
Mike West. 安全上下文. 2023年11月10日. CRD. URL: https://www.w3.org/TR/secure-contexts/
[URL]
Anne van Kesteren. URL 标准. Living Standard. 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?