互联网草案 Cookie:HTTP 状态管理机制 2026 年 6 月
Bingler 等 2026 年 12 月 20 日过期 [页]
工作组:
HTTP
互联网草案:
draft-ietf-httpbis-rfc6265bis-latest
废弃:
6265(如获批准)
发布于:
预期状态:
标准轨道
过期:
作者:
S. Bingler,
M. West,
Google LLC
J. Wilander,
Apple, Inc

Cookie:HTTP 状态管理机制

摘要

本文档定义了 HTTP Cookie 和 Set-Cookie 标头字段。这些 标头字段可由 HTTP 服务器用于在 HTTP 用户代理处存储状态(称为 cookie), 让服务器能够在基本无状态的 HTTP 协议之上维护有状态会话。 虽然 cookie 存在许多会削弱其安全性和隐私性的历史缺陷, 但 Cookie 和 Set-Cookie 标头字段在 Internet 上被广泛使用。 本文档废弃 RFC 6265。

关于本文档

此注释将在作为 RFC 发布前移除。

本文档的状态信息可在 https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/ 找到。

本文档的讨论在 HTTP 工作组邮件列表(mailto:ietf-http-wg@w3.org)上进行, 其归档位于 https://lists.w3.org/Archives/Public/ietf-http-wg/。 工作组信息可在 https://httpwg.org/ 找到。

此草案的源码和议题跟踪器可在 https://github.com/httpwg/http-extensions/labels/6265bis 找到。

本备忘录状态

此互联网草案的提交完全符合 BCP 78 和 BCP 79 的规定。

互联网草案是 Internet Engineering Task Force (IETF) 的工作文档。请注意,其他团体也可能将工作 文档作为互联网草案分发。当前互联网草案列表位于 https://datatracker.ietf.org/drafts/current/

互联网草案是最长有效期为六个月的草案文档, 并且可能随时被其他文档更新、替换或废弃。 将互联网草案用作参考材料,或将其作为“进行中的工作”之外的形式引用, 都是不恰当的。

此互联网草案将于 2026 年 12 月 20 日过期。

目录

1. 引言

本文档定义 HTTP Cookie 和 Set-Cookie 标头字段。使用 Set-Cookie 标头字段,HTTP 服务器可以向用户代理传递名称/值对和 相关元数据(称为 cookie)。当用户代理向服务器发出 后续请求时,用户代理会使用这些元数据和其他 信息来确定是否在 Cookie 标头字段中返回这些名称/值对。

虽然 cookie 表面上很简单,但它们有许多复杂性。例如, 服务器在向用户代理发送每个 cookie 时会指明其作用域。 该作用域表示用户代理应返回 cookie 的最长时间、用户代理应 向其返回 cookie 的服务器,以及该 cookie 适用的连接类型。

由于历史原因,cookie 包含若干安全和隐私缺陷。 例如,服务器可以指明某个 cookie 旨在用于“安全” 连接,但在存在主动网络攻击者时,Secure 属性并不提供 完整性。同样,给定主机的 cookie 会在该主机的所有端口之间共享, 尽管 Web 浏览器使用的通常 “同源策略”会隔离通过 不同端口获取的内容。

本规范适用于 cookie 生成服务器和 cookie 消费用户代理的开发者。第 3.2 节有助于阐明 每种实现类型的预期目标受众。

为了最大化与用户代理的互操作性,服务器在生成 cookie 时应 将自身限制在第 4 节中定义的行为良好配置文件内。

用户代理必须实现第 5 节中定义的更宽松处理规则, 以最大化与不符合第 4 节中定义的行为良好配置文件的现有服务器的 互操作性。

本文档规定这些标头字段在 Internet 上实际使用时的语法和语义。 特别地,本文档不会创建超出现今使用范围的新 语法或语义。第 4 节中提供的 cookie 生成建议代表当前 服务器行为的首选子集,而第 5 节中提供的更宽松 cookie 处理算法也不推荐现今使用的所有 语法和语义变体。在某些现有软件以重要方式不同于推荐协议时, 本文档包含一条说明该差异的注释。

本文档废弃 [RFC6265]

2. 约定

2.1. 一致性准则

本文档中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“NOT RECOMMENDED”、 “MAY”和“OPTIONAL”只有在像此处所示以全大写形式出现时,才应按照 BCP 14 [RFC2119] [RFC8174] 中的描述进行解释。

作为算法一部分以祈使语气表述的要求(例如“剥离 任何 前导空格字符”或“返回 false 并中止此算法”),应按照引入该算法时使用的 关键词(“MUST”、“SHOULD”、“MAY”等)的含义解释。

以算法或具体步骤表述的一致性要求可以用任何方式实现, 只要最终结果等价即可。特别地,本规范中定义的算法旨在 易于理解,而不旨在高性能。

2.2. 语法表示法

本规范使用 [RFC5234] 的扩展巴科斯-瑙尔范式(ABNF)表示法。

下列核心规则按引用纳入,如 [RFC5234] 附录 B.1 所定义:ALPHA(字母)、CR(回车)、CRLF(CR LF)、CTLs (控制字符)、DIGIT(十进制 0-9)、DQUOTE(双引号)、HEXDIG (十六进制 0-9/A-F/a-f)、LF(换行)、NUL(空八位组)、OCTET(除 NUL 外的任意 8 位数据序列)、SP(空格)、HTAB(水平制表符)、 CHAR(任意 [USASCII] 字符)、VCHAR(任意 可见 [USASCII] 字符), 以及 WSP(空白)。

OWS(可选空白)和 BWS(不良空白)规则定义于 [HTTP] 的第 5.6.3 节

2.3. 术语

术语“user agent”、“client”、“server”、“proxy”和“origin server”与 HTTP/1.1 规范([HTTP] 的第 3 节)中的含义相同。

request-host 是用户代理所知的主机名称,用户代理正向该主机 发送 HTTP 请求,或正从该主机接收 HTTP 响应(即,它向其发送相应 HTTP 请求的主机名称)。

术语 request-uri 指 [HTTP] 第 7.1 节中定义的“target URI”。

两个八位组序列被称为以大小写不敏感方式彼此匹配,当且 仅当它们在 [RFC4790] 定义的 i;ascii-casemap 排序规则下等价。

术语 string 表示非 NUL 八位组序列。

术语“active browsing context”、“active document”、“ancestor navigables”、 “container document”、“content navigable”、“dedicated worker”、“Document”、 “inclusive ancestor navigables”、“navigable”、“navigate”、“opaque origin”、 “sandboxed origin browsing context flag”、“shared worker”、“the worker's Documents”、“top-level traversable”和“WorkerGlobalScope”定义于 [HTML]

“Service Workers”定义于 Service Workers 规范 [SERVICE-WORKERS]

术语“origin”、从 URI 推导 origin 的机制,以及 origin 的 “the same”匹配算法定义于 [RFC6454]

“Safe” HTTP 方法包括 GETHEADOPTIONSTRACE,如 [HTTP] 第 9.2.1 节所定义。

域的“public suffix”是由公共注册机构控制的域部分,例如“com”、 “co.uk”和“pvt.k12.wy.us”。域的 “registrable domain”是该域的公共后缀加上其左侧的标签。 也就是说,对于 https://www.site.example,公共后缀是 example, 而 可注册域是 site.example。有关安全 注意事项,请参见 第 8.9 节

术语“request”以及请求的“client”、“current url”、“method”、 “target browsing context”和“url list”定义于 [FETCH]

术语“non-HTTP APIs”指用于设置和 检索 cookie 的非 HTTP 机制,例如向脚本暴露 cookie 的 Web 浏览器 API。

术语“top-level navigation”指顶级 traversable 的导航。

2.4. 名称解析系统

虽然本文档并未严格规定用于 cookie 的任何特定名称解析 系统,但它确实要求该系统只使用 [USASCII] 字符,或使用 ASCII 兼容编码(ACE)。由于域名 系统(DNS)是典型且传统的示例,本文档将 以 DNS 的术语引用名称解析。

直接暴露非 ASCII 字符(例如 Unicode)的名称解析系统不在本文档范围内。

3. 概述

本节概述一种方式,使源服务器能够向 用户代理发送状态信息,并使用户代理能够将状态信息返回给源 服务器。

为了存储状态,源服务器在 HTTP 响应中包含 Set-Cookie 标头字段。在后续请求中,用户代理向源服务器返回 Cookie 请求 标头字段。Cookie 标头字段包含用户代理在先前 Set-Cookie 标头字段中接收的 cookie。 源服务器可以自由地忽略 Cookie 标头字段,或将其内容用于应用定义的目的。

源服务器可以随任何响应发送 Set-Cookie 响应标头字段。源 服务器可以在单个响应中包含多个 Set-Cookie 标头字段。 Cookie 或 Set-Cookie 标头字段的存在并不妨碍 HTTP 缓存存储和重用响应。

源服务器和中介不得将多个 Set-Cookie 标头 字段合并为单个标头字段。合并 HTTP headers 字段的通常机制(即,定义于 [HTTP] 的第 5.3 节的机制)可能会 改变 Set-Cookie 标头字段的语义,因为 %x2C(“,”)字符 在 Set-Cookie 中的使用方式与这种合并冲突。

例如,

Set-Cookie: a=b;path=/c,d=e

是有歧义的。它可能旨在表示两个 cookie:a=b 和 d=e,也可能表示一个 路径为 /c,d=e 的单个 cookie。

用户代理可以基于响应状态码或 用户代理的 cookie 策略忽略 Set-Cookie 标头字段(见第 5.3 节)。

注:cookie 的八位组必须作为 [USASCII] 字符处理。虽然 非 HTTP API 可能传递包含一个或多个 非 [USASCII] 字符的 set-cookie-string,但不应尝试 将这些八位组解释为除 [USASCII] 字符之外的任何内容。

3.1. 示例

使用 Set-Cookie 标头字段,服务器可以在 HTTP 响应中向用户代理发送一个短 字符串,该字符串将由用户代理在未来处于 cookie 作用域内的 HTTP 请求中 返回。例如,服务器可以向用户 代理发送一个名为 SID、值为 31d4d96e407aad42 的“会话标识符”。随后 用户代理在后续请求中返回该会话标识符。

== Server -> User Agent ==

Set-Cookie: SID=31d4d96e407aad42

== User Agent -> Server ==

Cookie: SID=31d4d96e407aad42

服务器可以使用 Path 和 Domain 属性更改 cookie 的默认作用域。例如,服务器可以指示用户代理 将 cookie 返回给 site.example 的每个路径和每个子域。

== Server -> User Agent ==

Set-Cookie: SID=31d4d96e407aad42; Path=/; Domain=site.example

== User Agent -> Server ==

Cookie: SID=31d4d96e407aad42

如下一示例所示,服务器可以在 用户 代理处存储多个 cookie。例如,服务器可以通过返回两个 Set-Cookie 标头字段来存储会话标识符以及 用户的首选语言。请注意, 服务器使用 Secure 和 HttpOnly 属性为更敏感的会话标识符提供 额外安全保护(见 第 4.1.2 节)。

== Server -> User Agent ==

Set-Cookie: SID=31d4d96e407aad42; Path=/; Secure; HttpOnly
Set-Cookie: lang=en-US; Path=/; Domain=site.example

== User Agent -> Server ==

Cookie: SID=31d4d96e407aad42; lang=en-US

请注意,上述 Cookie 标头字段包含两个 cookie,一个名为 SID, 另一个名为 lang。

Cookie 名称区分大小写,这意味着如果服务器向用户代理 发送两个仅名称大小写不同的 Set-Cookie 标头字段,用户 代理将在后续请求中存储并返回这两个 cookie。

== Server -> User Agent ==

Set-Cookie: SID=31d4d96e407aad42
Set-Cookie: sid=31d4d96e407aad42

== User Agent -> Server ==

Cookie: SID=31d4d96e407aad42; sid=31d4d96e407aad42

如果服务器希望用户代理在多个“会话”(例如用户代理重启)之间 持久保存 cookie,服务器可以在 Expires 属性中指定过期日期。请注意,如果用户代理的 cookie 存储 超出配额,或用户手动删除服务器的 cookie,用户代理可能会在过期日期之前 删除该 cookie。

== Server -> User Agent ==

Set-Cookie: lang=en-US; Expires=Wed, 09 Jun 2026 10:18:14 GMT

== User Agent -> Server ==

Cookie: SID=31d4d96e407aad42; lang=en-US

最后,为了移除 cookie,服务器返回一个带有过去过期日期的 Set-Cookie 标头字段。只有当 Set-Cookie 标头字段中的 Path 和 Domain 属性 与创建 cookie 时使用的值匹配时,服务器才能成功移除该 cookie。

== Server -> User Agent ==

Set-Cookie: lang=; Expires=Sun, 06 Nov 1994 08:49:37 GMT

== User Agent -> Server ==

Cookie: SID=31d4d96e407aad42

3.2. 应实现哪些要求

接下来的两个小节,即第 4 节第 5 节,讨论 两种不同实现类型的要求集合。本节旨在帮助实现者确定哪一组要求 最适合其目标。选择错误的要求集合可能导致与其他 cookie 实现 缺乏兼容性。

重要的是要注意,兼容性的含义会因 实现者的目标而异。这些差异随着时间推移而形成, 既源自有意和无意的规范变更、规范解释, 也源自历史实现差异。

本节大致将 cookie 规范的实现者分为两类: 生产者和消费者。这些并非正式术语,仅在此用于 帮助读者对用例形成直观理解。

4. 服务器要求

本节描述 Cookie 和 Set-Cookie 标头字段的行为良好配置文件的 语法和语义。

5. 用户代理要求

本节以足够详细的方式规定 Cookie 和 Set-Cookie 标头字段, 使精确实现这些要求的用户代理能够 与现有服务器互操作(即使这些服务器不符合第 4 节中描述的 行为良好配置文件)。

用户代理可以执行比本文规定更多的限制(例如, 由其 cookie 策略规定的限制,如第 7.2 节所述)。 但是,此类附加限制可能会降低用户 代理与现有服务器互操作的可能性。

5.1. 子组件 算法

本节定义用户代理用于处理 Cookie 和 Set-Cookie 标头字段的 特定子组件的一些算法。

5.1.2. 规范化 主机名

规范化主机名是由以下 算法生成的字符串:

  1. 将主机名转换为一系列单独的域名 标签。

  2. 所有标签都必须是 U-label、A-label 或 Non-Reserved LDH(NR-LDH) label 之一(见 [RFC5890] 的第 2.3.1 节)。如果任何标签不是其中之一, 则中止此算法,并规范化主机名失败。

  3. 将每个 U-label 转换为 A-label(见 [RFC5890] 的第 2.3.2.1 节)。

  4. 如果任何标签是 Fake A-label,则中止此算法, 并规范化主机名失败。

  5. 连接生成的各标签,并以 %x2E (“.”)字符分隔。

5.1.3. 域匹配

注:此算法预期两个输入均已规范化。

如果以下条件中至少有一个成立,则称一个字符串 domain-matches 给定的域字符串:

  • 域字符串与该字符串完全相同。(请注意, 此时域 字符串和该字符串都已被规范化为小写。)

  • 以下所有条件均成立:

    • 域字符串是该 字符串的后缀。

    • 该字符串中未 包含在域 字符串内的最后一个字符是 %x2E(“.”)字符。

    • 该字符串是主机名(即,不是 IP 地址)。

5.2. “same-site”和 “cross-site”请求

如果两个 origin 满足 [SAMESITE] 中定义的“same site”准则,则它们是 same-site。 如果以下准则为真,则请求是“same-site”:

  1. 该请求不是通过用户界面元素触发的 重新加载导航的结果(由 用户代理定义;例如,用户点击工具栏上的刷新按钮触发的请求)。

  2. 请求的 current url 的 origin 与请求的 client 的“site for cookies”(它是一个 origin)是 same-site,或者请求没有 client,或请求的 client 为 null。

通过用户界面元素触发的重新加载导航所产生的请求, 如果被重新加载的文档最初是通过 same-site 请求导航到的, 则这些请求是 same-site。不是“same-site”的请求 则是“cross-site”。

请求的 client 的“site for cookies”会根据其 client 类型计算,如以下小节所述:

5.2.1. 基于 Document 的 请求

用户代理地址栏中显示的 URI 是唯一 直接暴露给用户的安全 上下文,因此也是用户可以合理 依赖以判断其是否信任某个特定网站的唯一信号。该 URI 的 origin 表示用户最可能认为 自己正在交互的上下文。此 origin,即顶级 traversable 的活动 document 的 origin,被定义为“top-level origin”。

对于显示在顶级 traversable 中的 document, 该 document 的 “site for cookies”是 top-level origin。

对于 container document,必须审计一个 document 的每个 ancestor navigables 的活动 document 的 origin,以处理 [RFC7034] 的第 4 节中描述的 “multiple-nested scenarios”。当且仅当 top-level origin 与 document 的 origin,以及该 document 的 每个 ancestor document 的 origin 均为 same-site 时,document 的 “site for cookies”才是 top-level origin。否则,其“site for cookies”是一个设置为 opaque origin 的 origin。

给定一个 Document(document),以下算法 返回其“site for cookies”:

  1. top-documentdocument 的 navigable 的 top-level traversable 中的活动 document。

  2. 如果设置了 top-document 的 sandboxed origin browsing context flag,则令 top-origintop-document 的 URI 的 origin;否则为 top-document 的 origin。

  3. documents 为一个列表,由 document 的 inclusive ancestor navigables 的活动 document 组成。

  4. documents 中的每个 item

    1. 如果设置了 item 的 sandboxed origin browsing context flag,则令 originitem 的 URI 的 origin;否则为 item 的 origin。

    2. 如果 origintop-origin 不是 same-site,则返回一个设置为 opaque origin 的 origin。

  5. 返回 top-origin

注:此算法仅在从 top-documentdocument 的整个 document 链 全部处于活动状态时适用。

5.2.2. 基于 Worker 的 请求

Worker 驱动的请求不像 document 驱动的 请求那样清晰, 因为顶级 traversable 与 worker 之间没有明确链接。 对于 Service Workers [SERVICE-WORKERS] 尤其如此,它们可能 在后台执行代码,而没有任何可见 document。

5.2.2.1. Dedicated 和 Shared Workers

Dedicated worker 很简单,因为每个 dedicated worker 绑定到 且仅绑定到一个 document。如果 worker 的 origin 与 document 的 “site for cookies”为 same-site,则 worker 的“site for cookies”是该 document 的 “site for cookies”;否则其“site for cookies”是一个设置为 opaque origin 的 origin。

Shared worker 可以同时绑定到多个 document。 由于这些 document 很可能具有不同的“site for cookies”值, 因此当这些值并非全部与 worker 的 origin 为 same-site 时, worker 的“site for cookies”将是一个设置为 opaque origin 的 origin; 而当这些值一致时,则为 worker 的 origin。

给定一个 WorkerGlobalScope(worker), 以下算法返回其“site for cookies”:

  1. siteworker 的 origin。

  2. worker 的 Documents 中的每个 document

    1. document-sitedocument 的“site for cookies”(如 第 5.2.1 节所定义)。

    2. 如果 document-sitesite 不是 same-site,则返回一个设置为 opaque origin 的 origin。

  3. 返回 site

5.2.2.2. Service Workers

Service Workers 更复杂,因为它们作为一个 完全独立的 执行上下文运行,并且只与注册它们的 Document 有间接关系。

用户代理处理 Service Workers 的方式可能不同,但 用户代理应 匹配 [SERVICE-WORKERS] 规范。

用户代理可以忽略 100 级 状态码响应中包含的 Set-Cookie 标头字段, 或基于其 cookie 策略(见第 7.2 节)忽略该字段。

所有其他 Set-Cookie 标头字段应根据第 5.6 节处理。 也就是说,非 100 级状态码响应中包含的 Set-Cookie 标头字段 (包括 400 级和 500 级状态码响应中的那些) 应被处理,除非根据用户代理的 cookie 策略被忽略。

用户代理关于 cookie 名称前缀的要求与 服务器的要求(第 4.1.3 节)略有不同, 因为 UA 必须以大小写不敏感方式匹配前缀字符串。

前缀的规范性要求详述于 第 5.7 节中定义的存储模型 算法。

这是因为一些服务器会以大小写不敏感方式处理 cookie, 从而 无意中错误大写前缀并接受错误大写的前缀。

例如,如果服务器发送以下 Set-Cookie 标头 字段

Set-Cookie: __SECURE-SID=12345

给一个以大小写敏感方式检查前缀的 UA,它将接受此 cookie, 而服务器会错误地认为该 cookie 受到 拼写为 __Secure- 的 cookie 所具有的相同保证约束。

此外,如果攻击者故意 错误大写某个 cookie 以冒充带前缀 cookie,则服务器易受攻击。例如, 某站点已经有一个 cookie __Secure-SID=12345,并且攻击者以某种方式 向以大小写敏感方式检查前缀的 UA 发送以下该站点的 Set-Cookie 标头字段。

Set-Cookie: __SeCuRe-SID=evil

下次用户访问该站点时,UA 会发送这两个 cookie:

Cookie: __Secure-SID=12345; __SeCuRe-SID=evil

服务器由于大小写不敏感,将无法区分这两个 cookie,从而使攻击者能够攻陷该站点。

为防止这些问题,UA 必须以 大小写不敏感方式匹配 cookie 名称前缀。

注:具有不同名称的 cookie 仍会被 UA 视为不同 cookie。 因此,__Secure-foo=bar__secure-foo=baz 可以作为不同的 cookie 同时存在,并且二者都会应用 __Secure- 前缀的要求。

以下是会被符合要求的用户代理拒绝的 Set-Cookie 标头字段示例。

Set-Cookie: __Secure-SID=12345; Domain=site.example
Set-Cookie: __secure-SID=12345; Domain=site.example
Set-Cookie: __SECURE-SID=12345; Domain=site.example
Set-Cookie: __Host-SID=12345
Set-Cookie: __host-SID=12345; Secure
Set-Cookie: __host-SID=12345; Domain=site.example
Set-Cookie: __HOST-SID=12345; Domain=site.example; Path=/
Set-Cookie: __Host-SID=12345; Secure; Domain=site.example; Path=/
Set-Cookie: __host-SID=12345; Secure; Domain=site.example; Path=/
Set-Cookie: __HOST-SID=12345; Secure; Domain=site.example; Path=/

而以下 Set-Cookie 标头字段如果从 安全源设置,则会被接受。

Set-Cookie: __Secure-SID=12345; Domain=site.example; Secure
Set-Cookie: __secure-SID=12345; Domain=site.example; Secure
Set-Cookie: __SECURE-SID=12345; Domain=site.example; Secure
Set-Cookie: __Host-SID=12345; Secure; Path=/
Set-Cookie: __host-SID=12345; Secure; Path=/
Set-Cookie: __HOST-SID=12345; Secure; Path=/

5.7. 存储模型

用户代理存储每个 cookie 的以下字段:name、value、 expiry-time、domain、path、creation-time、last-access-time、 persistent-flag、host-only-flag、secure-only-flag、http-only-flag 和 same-site-flag。

当用户代理从 request-uri “接收一个 cookie”,其名称为 cookie-name,值为 cookie-value,属性为 cookie-attribute-list 时, 用户代理必须按如下方式处理该 cookie:

  1. 用户代理可以完全忽略收到的 cookie。参见 第 5.3 节

  2. 如果 cookie-name 为空且 cookie-value 为空,则中止此 算法并 完全忽略该 cookie。

  3. 如果 cookie-name 或 cookie-value 包含 %x00-08 / %x0A-1F / %x7F 字符(不包括 HTAB 的 CTL 字符), 则中止此算法并完全忽略该 cookie。

  4. 如果 cookie-name 和 cookie-value 的长度之和超过 4096 个八位组,则中止此算法并完全忽略该 cookie。

  5. 创建一个新 cookie,其 name 为 cookie-name,value 为 cookie-value。将 creation-time 和 last-access-time 设置为当前日期和时间。

  6. 如果 cookie-attribute-list 包含一个 attribute-name 为“Max-Age”的属性:

    1. 将 cookie 的 persistent-flag 设置为 true。

    2. 将 cookie 的 expiry-time 设置为 cookie-attribute-list 中最后一个 attribute-name 为 “Max-Age”的属性的 attribute-value。

    否则,如果 cookie-attribute-list 包含一个 attribute-name 为“Expires”的属性(且不包含 attribute-name 为“Max-Age”的属性):

    1. 将 cookie 的 persistent-flag 设置为 true。

    2. 将 cookie 的 expiry-time 设置为 cookie-attribute-list 中最后一个 attribute-name 为 “Expires”的属性的 attribute-value。

    否则:

    1. 将 cookie 的 persistent-flag 设置为 false。

    2. 将 cookie 的 expiry-time 设置为最晚的 可表示日期。

  7. 如果 cookie-attribute-list 包含一个 attribute-name 为“Domain”的属性:

    1. 令 domain-attribute 为 cookie-attribute-list 中最后一个同时具有 attribute-name 为“Domain”且 attribute-value 长度不超过 1024 个八位组的属性的 attribute-value。(请注意,前导 %x2E (“.”)若存在则会被忽略,即使该字符并不 被允许。)

    否则:

    1. 令 domain-attribute 为空字符串。

  8. 如果 domain-attribute 包含不属于 CHAR 的字符,则中止 此算法并完全忽略该 cookie。

  9. 如果用户代理被配置为拒绝“public suffixes”,且 domain-attribute 是 public suffix:

    1. 令 request-host-canonical 为规范化后的 request-host。

    2. 如果 request-host 未能规范化,则中止 此算法并 完全忽略该 cookie。

    3. 如果 domain-attribute 与 request-host-canonical 完全相同:

      1. 令 domain-attribute 为空 字符串。

      否则:

      1. 中止此算法并完全忽略该 cookie。

    注:此步骤防止 attacker.example 通过设置一个 Domain 属性为“example”的 cookie 来破坏 site.example 的完整性。

  10. 如果 domain-attribute 非空:

    1. 如果 request-host-canonical 不 domain-match (见第 5.1.3 节) domain-attribute:

      1. 中止此算法并完全忽略该 cookie。

      否则:

      1. 将 cookie 的 host-only-flag 设置为 false。

      2. 将 cookie 的 domain 设置为 domain-attribute。

    否则:

    1. 将 cookie 的 host-only-flag 设置为 true。

    2. 将 cookie 的 domain 设置为 request-host-canonical。

  11. 如果 cookie-attribute-list 包含一个 attribute-name 为“Path”的属性,则将 cookie 的 path 设置为 cookie-attribute-list 中最后一个同时具有 attribute-name 为“Path”且 attribute-value 长度不 超过 1024 个八位组的属性的 attribute-value。否则,将 cookie 的 path 设置为 request-uri 的 default-path。

  12. 如果 cookie-attribute-list 包含一个 attribute-name 为“Secure”的属性,则将 cookie 的 secure-only-flag 设置为 true。 否则,将 cookie 的 secure-only-flag 设置为 false。

  13. 如果 request-uri 不表示一个“secure”连接(由 用户代理定义),且 cookie 的 secure-only-flag 为 true,则中止这些 步骤并完全忽略该 cookie。

  14. 如果 cookie-attribute-list 包含一个 attribute-name 为“HttpOnly”的属性,则将 cookie 的 http-only-flag 设置为 true。 否则,将 cookie 的 http-only-flag 设置为 false。

  15. 如果 cookie 是从“non-HTTP”API 接收的,且 cookie 的 http-only-flag 为 true,则中止此算法并完全忽略该 cookie。

  16. 如果 cookie 的 secure-only-flag 为 false,且 request-uri 不表示一个“secure”连接,那么如果 cookie 存储包含一个或多个满足 以下所有准则的 cookie,则中止此算法并完全忽略 该 cookie:

    1. 其 name 与新创建的 cookie 的 name 匹配。

    2. 其 secure-only-flag 为 true。

    3. 其 domain domain-matches(见第 5.1.3 节)新创建 cookie 的 domain,或反之亦然。

    4. 新创建 cookie 的 path path-matches 现有 cookie 的 path。

    注:path 比较不是对称的,只确保 新创建的非安全 cookie 不会覆盖现有的安全 cookie,从而对 cookie-fixing 攻击提供一定缓解。也就是说, 给定一个名为 'a'、path 为 '/login' 的现有安全 cookie, 可以为 path '/' 或 '/foo' 设置一个名为 'a' 的 非安全 cookie,但不能为 path '/login' 或 '/login/en' 设置。

  17. 如果 cookie-attribute-list 包含一个 attribute-name 为“SameSite”且 attribute-value 为“Strict”、“Lax”或 “None”的属性,则将 cookie 的 same-site-flag 设置为 cookie-attribute-list 中最后一个 attribute-name 为“SameSite”的属性的 attribute-value。 否则,将 cookie 的 same-site-flag 设置为“Default”。

  18. 如果 cookie 的 same-site-flag 不是“None”:

    1. 如果 cookie 是从“non-HTTP”API 接收的,且 该 API 是从一个 navigable 的活动 document 调用的,而其“site for cookies” 与 top-level origin 不是 same-site,则中止此算法并 完全忽略新创建的 cookie。

    2. 如果 cookie 是从“same-site”请求接收的 (如第 5.2 节所定义),则跳过 剩余子步骤并继续 处理该 cookie。

    3. 如果 cookie 是从正在导航 top-level traversable [HTML] 的请求接收的 (例如,如果请求的“reserved client”为 null,或是一个其“target browsing context”的 navigable 为 top-level traversable 的环境),则跳过 剩余子步骤并继续处理该 cookie。

      注:顶级导航可以创建任何 SameSite 值的 cookie,即使该新 cookie 若在导航前已经存在也不会随 该请求一起发送。

    4. 中止此算法并完全忽略新创建的 cookie。

  19. 如果 cookie 的“same-site-flag”为“None”,则中止此算法并 完全忽略该 cookie,除非 cookie 的 secure-only-flag 为 true。

  20. 如果 cookie-name 以大小写不敏感方式匹配字符串 “__Secure-”开头,则中止此算法并完全忽略该 cookie,除非 cookie 的 secure-only-flag 为 true。

  21. 如果 cookie-name 以大小写不敏感方式匹配字符串 “__Host-”开头,则中止此算法并完全忽略该 cookie,除非 cookie 满足以下所有准则:

    1. cookie 的 secure-only-flag 为 true。

    2. cookie 的 host-only-flag 为 true。

    3. cookie-attribute-list 包含一个 attribute-name 为“Path”的属性,且 cookie 的 path 为 /

  22. 如果 cookie-name 为空,并且以下任一 条件为 true,则中止此算法并完全忽略该 cookie:

    • cookie-value 以大小写不敏感方式匹配字符串 “__Secure-”开头

    • cookie-value 以大小写不敏感方式匹配字符串 “__Host-”开头

  23. 如果 cookie 存储包含一个与新创建 cookie 的 name、domain、 host-only-flag 和 path 相同的 cookie:

    1. 令 old-cookie 为与新创建 cookie 具有相同 name、domain、 host-only-flag 和 path 的现有 cookie。(请注意,此 算法维持以下不变量:至多存在一个这样的 cookie。)

    2. 如果新创建的 cookie 是从 “non-HTTP”API 接收的,且 old-cookie 的 http-only-flag 为 true,则中止此算法并 完全忽略新创建的 cookie。

    3. 更新新创建 cookie 的 creation-time 以匹配 old-cookie 的 creation-time。

    4. 从 cookie 存储中移除 old-cookie。

  24. 将新创建的 cookie 插入 cookie 存储。

如果 cookie 的 expiry date 在过去,则该 cookie 为“expired”。

如果 cookie 存储中在任何时候存在 expired cookie, 用户代理必须从 cookie 存储中逐出所有 expired cookie。

如果共享同一 domain 字段的 cookie 数量超过某个 由实现定义的上限(例如 50 个 cookie),则用户代理可以在任何时候从 cookie 存储中 “remove excess cookies”。

如果 cookie 存储超过某个预定上限(例如 3000 个 cookie),则用户代理可以在任何时候从 cookie 存储中 “remove excess cookies”。

当用户代理从 cookie 存储中移除 excess cookies 时,用户 代理必须按以下优先级顺序逐出 cookie:

  1. Expired cookies。

  2. secure-only-flag 为 false,且与超过预定数量的 其他 cookie 共享 domain 字段的 cookie。

  3. 与超过预定数量的 其他 cookie 共享 domain 字段的 cookie。

  4. 所有 cookie。

如果两个 cookie 具有相同的移除优先级,则用户代理必须先逐出 last-access-time 最早的 cookie。

当“the current session is over”(由用户代理定义)时,用户 代理必须从 cookie 存储中移除所有 persistent-flag 设置为 false 的 cookie。

5.8. 检索模型

本节定义如何以 cookie-string 的形式 从 cookie 存储中检索 cookie。“retrieval”是任何需要生成 cookie-string 的事件。例如,为了构建 HTTP 请求的 Cookie 标头字段,可能会发生 retrieval;或者为了从提供 cookie 访问能力的 “non-HTTP”API 调用返回 cookie-string,可能需要 retrieval。retrieval 具有相关联的 URI、same-site 状态和类型, 它们根据 retrieval 类型在下文定义。

5.8.2. 非 HTTP API

用户代理可以实现可用于访问 已存储 cookie 的“non-HTTP”API。

用户代理可以在某些上下文中返回空 cookie-string, 例如 当 retrieval 发生在第三方上下文中时(见 第 7.1 节)。

如果用户代理确实为一次具有关联 Document 的“non-HTTP” API 调用返回 cookie, 则用户代理必须按第 5.8.3 节中定义的算法计算 cookie-string,其中 retrieval 的 URI 由调用者定义(见 [DOM-DOCUMENT-COOKIE]), 如果 Document 的“site for cookies”与第 5.2.1 节中定义的 top-level origin 为 same-site, 则 retrieval 的 same-site 状态为“same-site”(否则为 “cross-site”),且 retrieval 的类型 为“non-HTTP”。

5.8.3. 检索 算法

给定一个 cookie 存储和一次 retrieval,以下算法 从给定 cookie 存储返回 cookie-string。

  1. 令 retrieval-host-canonical 为 retrieval 的 URI 的 规范化 host。

  2. 如果 retrieval 的 URI 的 host 未能 规范化,则中止此 算法。

  3. 令 cookie-list 为 cookie 存储中满足以下所有 要求的 cookie 集合:

    • 二者之一:

      • cookie 的 host-only-flag 为 true,且 retrieval-host-canonical 与 cookie 的 domain 完全相同。

      或:

      • cookie 的 host-only-flag 为 false,且 retrieval-host-canonical domain-matches(见第 5.1.3 节)cookie 的 domain。

      • 对于配置为拒绝 “public suffixes”的用户代理,cookie 的 domain 不是 public suffix。

      注:public suffix list 可能在 cookie 创建后发生改变。 如果该改变导致 cookie 的 domain 变成 public suffix, 那么如果现在创建该 cookie,它会在 创建期间被拒绝。(见第 5.7 节步骤 9)。

    • retrieval 的 URI 的 path path-matches cookie 的 path。

    • 如果 cookie 的 secure-only-flag 为 true, 则 retrieval 的 URI 必须 表示一个“secure”连接(由用户代理定义)。

      注:“secure”连接的概念不由本文档定义。 通常,用户代理认为一个连接是安全的,如果该连接 使用了传输层安全性,例如 SSL 或 TLS [TLS13],或如果该 host 是 受信任的。例如,大多数用户代理认为“https”是一个 表示安全协议的 scheme,而“localhost”是受信任的 host。

    • 如果 cookie 的 http-only-flag 为 true, 则当 retrieval 的 type 为“non-HTTP”时 排除该 cookie。

    • 如果 cookie 的 same-site-flag 不是“None” 且 retrieval 的 same-site 状态为“cross-site”,则排除该 cookie,除非满足以下所有 条件:

      • retrieval 的 type 为 “HTTP”。

      • same-site-flag 为“Lax”或 “Default”。

      • 与 retrieval 关联的 HTTP 请求使用“safe”方法。

      • 与 retrieval 关联的 HTTP 请求的 target browsing context 是 active browsing context 或 top-level traversable。

  4. 用户代理应按以下顺序排序 cookie-list:

    • path 较长的 cookie 列在 path 较短的 cookie 之前。

    • 在 path 字段等长的 cookie 中, creation-time 较早的 cookie 列在 creation-time 较晚的 cookie 之前。

    注:并非所有用户代理都按此顺序排序 cookie-list,但此顺序 反映了本文档编写时的常见实践,并且历史上 曾有服务器(错误地)依赖此顺序。

  5. 将 cookie-list 中每个 cookie 的 last-access-time 更新为 当前日期和时间。

  6. 按顺序处理 cookie-list 中的每个 cookie, 将 cookie-list 序列化为 cookie-string:

    1. 如果 cookie 的 name 非空,则输出 cookie 的 name,后跟 %x3D(“=”)字符。

    2. 如果 cookie 的 value 非空,则输出 cookie 的 value。

    3. 如果该 cookie 不是 cookie-list 中的最后一个 cookie,则输出 字符 %x3B 和 %x20(“; ”)。

6. 实现注意事项

6.1. 限制

实际的用户代理实现对它们可以存储的 cookie 数量和大小有限制。通用用户代理应提供以下 最低能力:

  • 每个 domain 至少 50 个 cookie。

  • 总计至少 3000 个 cookie。

用户代理可以限制其存储的 cookie 最大数量,并且可以在任何时候逐出 任意 cookie(无论是应用户请求,还是由于 实现限制)。

请注意,对 cookie 最大数量的限制也会限制 已存储 cookie 的总大小,这是由于 第 5.6 节中必须强制执行的长度限制。

服务器应使用尽可能少且尽可能小的 cookie,以避免达到 这些实现限制,最大限度减少因 Cookie 标头字段包含在每个请求中而产生的网络带宽消耗,并避免达到 服务器标头字段限制(见第 4.2.1 节)。

如果用户代理由于可能在任何时候逐出任意 cookie 而未能在 Cookie 标头字段中返回一个或多个 cookie,则服务器应优雅降级。

6.2. 应用程序 编程接口

Cookie 和 Set-Cookie 标头字段采用如此深奥处理的一个原因是, 许多平台(包括服务器和用户代理)都为 cookie 提供基于字符串的 应用程序编程接口(API),要求 应用层程序员生成和解析 Cookie 和 Set-Cookie 标头字段所使用的语法,而许多程序员曾错误地这样做, 从而导致互操作性问题。

平台不应向 cookie 提供基于字符串的 API,而应提供 更具语义的 API。本文档无意推荐具体的 API 设计,但接受一个抽象的“Date”对象而不是序列化日期字符串 具有明显好处。

7. 隐私注意事项

Cookie 的主要隐私风险是其关联用户活动的能力。这 可能发生在单个站点上,但当活动被跨不同的、 看似无关的网站跟踪以构建用户画像时,问题最为严重。

随着时间推移,这种能力(在 [RFC2109] 及其所有后续规范中均被明确警告反对) 已因各种原因被广泛使用,包括:

虽然并非每种 cookie 使用都一定会带来隐私问题,但其潜在的滥用 已成为 Internet 社区和更广泛社会中的普遍关切。为回应这些 关切,用户代理 已经以各种方式主动限制 cookie 功能(如先前规范所允许和鼓励的那样), 同时避免破坏它们认为有益于 Web 健康的功能。

现在宣称应使用哪些具体机制来缓解 cookie 的隐私影响还为时过早; 用户代理当前持续改变其处理方式,最好被描述为能够为 最终共识提供输入的实验。

相反,本文档描述了有限的、通用的缓解措施,用于应对 与 cookie 相关的隐私风险,这些措施在本文写作时已得到广泛部署。预计实现 将继续进行实验,并随着时间推移对 cookie 施加更严格、更明确的限制。 本文档的未来版本可能会根据部署经验将这些机制编纂成规范。 如果当前依赖 cookie 的功能能够由单独的、有针对性的 机制支持,那么它们可能会被记录在单独的规范中,并且对 cookie 的更严格限制 可能变得可行。

请注意,cookie 并不是唯一可用于跨站点跟踪用户的机制, 因此,虽然这些缓解措施对于改善 Web 隐私是必要的, 但仅靠它们本身并不足够。

7.1. 第三方 Cookie

“third-party”或 cross-site cookie 是指与嵌入内容(例如 脚本、图像、样式表、框架)相关联的 cookie,这些内容来自不同于托管 主要资源的服务器(通常是用户正在查看的 Web 页面)。第三方 cookie 经常用于关联用户在不同站点上的活动。

由于其固有的隐私问题,大多数用户代理现在以 多种方式限制第三方 cookie。一些用户代理通过拒绝处理第三方 Set-Cookie 标头字段并拒绝发送第三方 Cookie 标头字段来完全阻止第三方 cookie。 一些用户代理基于 first-party 上下文对 cookie 进行分区, 使得发送的 cookie 会根据正在浏览的站点而不同。一些用户代理基于 用户代理 cookie 策略和/或用户控制来阻止 cookie。

虽然本文档不认可或要求采用特定方法,但建议 用户代理采用一种第三方 cookie 策略,该策略在兼容性约束 允许的范围内尽可能严格。因此,在可预见的未来,资源不能依赖 第三方 cookie 会被用户代理一致对待。

7.3. 用户控制

用户代理应向用户提供一种机制,用于管理 cookie 存储中存储的 cookie。例如,用户代理可以让用户删除 在指定时间段内接收的所有 cookie,或删除与 特定 domain 相关的所有 cookie。此外,许多用户代理包含一个用户界面 元素,使用户能够检查其 cookie 存储中存储的 cookie。

用户代理应向用户提供一种禁用 cookie 的机制。当 cookie 被禁用时,用户代理不得在出站 HTTP 请求中包含 Cookie 标头字段, 并且用户代理不得处理入站 HTTP 响应中的 Set-Cookie 标头字段。

用户代理可以提供更改 cookie 策略的方式(见 第 7.2 节)。

用户代理可以向用户提供一种选项,以防止 cookie 跨会话持久存储。在如此配置时,用户代理必须将所有 收到的 cookie 都视为其 persistent-flag 被设置为 false。一些流行的 用户代理通过“private browsing”模式公开此功能 [Aggarwal2010]

7.4. 过期日期

尽管服务器可以将 cookie 的过期日期设置到遥远的 未来, 但大多数用户代理实际上不会将 cookie 保留数十年。 与其选择不必要地长的过期期限,服务器应通过 根据 cookie 的用途选择合理的 cookie 过期期限来提升用户 隐私。例如,一个典型的会话标识符合理地 可被设置为在两周后过期。

8. 安全注意事项

8.1. 概述

Cookie 存在许多安全陷阱。本节概述其中一些 较突出的 问题。

特别是,cookie 鼓励开发者依赖 ambient authority 进行身份验证,常常变得易受 cross-site request forgery [CSRF] 等攻击。此外,在 cookie 中存储会话 标识符时,开发者 常常会产生 session fixation 漏洞。

传输层加密,例如 HTTPS 中采用的加密,为防御针对 cookie 的网络攻击 提供了重要的一层防护。然而,由于 cookie 协议本身固有的漏洞(见下文“Weak Confidentiality”和“Weak Integrity”),它 不足以完全防止网络攻击者获取或 更改受害者的 cookie。此外,默认情况下,即使与 HTTPS 结合使用, cookie 也不针对网络攻击者提供机密性或完整性。这意味着 cookie 需要显式指定任何保护性属性。例如, cookie:

Set-Cookie: a=b

没有指定 Secure 属性,因此无论其最初是在何种连接类型上 创建的,它都可在安全和不安全连接上访问。 这种行为可能允许攻击者读取或修改该 cookie。

8.2. 环境授权

使用 cookie 验证用户身份的服务器可能遭受安全 漏洞,因为一些用户代理允许远程方从用户代理发出 HTTP 请求 (例如,通过 HTTP 重定向或 HTML 表单)。在发出 这些请求时,即使远程方不知道 cookie 的内容, 用户代理也会附加 cookie,从而可能让远程方在一个疏忽的服务器上行使 授权。

虽然这种安全问题有许多名称(例如 cross-site request forgery、confused deputy),但问题源于 cookie 是一种 ambient authority。Cookie 鼓励服务器运营者将 designation (以 URL 的形式)与 authorization(以 cookie 的形式)分离。 因此,用户代理可能会为攻击者指定的资源提供授权, 可能导致服务器或其客户端 执行攻击者指定的操作,就好像这些操作已由 用户授权一样。

服务器运营者可以考虑不要使用 cookie 进行授权,而是通过将 URL 视为 capability 来纠缠 designation 和 authorization。 这种方法不是将秘密存储在 cookie 中,而是将 秘密存储在 URL 中,要求远程实体自行提供该秘密。 虽然这种方法并非万灵药,但审慎应用这些 原则可以带来更健壮的安全性。

8.3. 明文

除非通过安全通道(例如 TLS [TLS13])发送,否则 Cookie 和 Set-Cookie 标头字段中的信息会以明文传输。

  1. 这些标头字段中传达的所有敏感信息都会 暴露给 窃听者。

  2. 恶意中介可能在标头字段沿任一 方向传输时修改这些标头字段, 产生不可预测的结果。

服务器在将 cookie 传输给用户代理时(即使通过安全通道发送 cookie),也应加密并签名 cookie 的内容(使用服务器期望的任何格式)。 然而,加密和签名 cookie 内容并不能防止攻击者将 cookie 从一个用户 代理移植到另一个用户代理,或在稍后时间重放该 cookie。

除了加密并签名每个 cookie 的内容之外,需要更高安全级别的 服务器应仅在安全通道上使用 Cookie 和 Set-Cookie 标头字段。在安全通道上使用 cookie 时, 服务器应为每个 cookie 设置 Secure 属性(见第 4.1.2.5 节)。如果服务器没有设置 Secure 属性, 安全通道提供的保护将基本失去意义。

例如,考虑一个将会话标识符存储在 cookie 中,并且通常通过 HTTPS 访问的 Webmail 服务器。如果服务器没有在其 cookie 上设置 Secure 属性,主动网络攻击者可以拦截用户代理发出的任意 出站 HTTP 请求,并将该请求重定向到 通过 HTTP 访问的 Webmail 服务器。即使 Webmail 服务器没有监听 HTTP 连接,用户代理仍然会在请求中包含 cookie。 主动网络攻击者可以拦截这些 cookie,针对 服务器重放它们,并获知用户电子邮件的内容。相反,如果服务器在其 cookie 上设置了 Secure 属性,则用户代理不会在明文请求中 包含这些 cookie。

8.4. 会话标识符

服务器通常不会直接在 cookie 中存储会话信息(在那里它可能 暴露给攻击者或被攻击者重放),而是在 cookie 中存储一个 nonce(或“session identifier”)。当服务器收到 带有 nonce 的 HTTP 请求时,服务器可以使用该 nonce 作为键, 查找与该 cookie 关联的状态信息。

使用会话标识符 cookie 可以限制攻击者在获知 cookie 内容时能够造成的损害,因为 nonce 只对 与服务器交互有用(不同于非 nonce 的 cookie 内容,后者本身 可能是敏感的)。此外,使用单个 nonce 可防止攻击者将 与服务器两次交互中的 cookie 内容“splicing”在一起,这 可能导致服务器表现出意外行为。

使用会话标识符并非没有风险。例如,服务器应 注意避免“session fixation”漏洞。session fixation 攻击 分三步进行。首先,攻击者将一个会话标识符 从其用户代理移植到受害者的用户代理。其次,受害者使用 该会话标识符与服务器交互,可能会将 用户的凭据或机密信息赋予该 会话标识符。第三,攻击者使用该会话标识符直接与服务器 交互,可能获得用户的授权或机密信息。

8.5. 弱保密性

Cookie 不提供按端口隔离。如果一个 cookie 可被运行在某个端口上的 服务读取,则该 cookie 也可被同一服务器另一个 端口上运行的服务读取。如果一个 cookie 可被某个端口上的服务写入, 则该 cookie 也可被同一服务器另一个端口上运行的服务写入。 因此,服务器不应在同一主机的不同端口上运行彼此不信任的 服务,同时又使用 cookie 存储安全敏感 信息。

Cookie 不提供按 scheme 隔离。尽管 cookie 最常与 http 和 https scheme 一起使用,但给定主机的 cookie 也可能 可用于其他 scheme,例如 ftp 和 gopher。虽然这种 按 scheme 隔离的缺失在允许访问 cookie 的非 HTTP API (例如 HTML 的 document.cookie API)中最为明显,但按 scheme 隔离的缺失 实际上也存在于处理 cookie 本身的要求中(例如, 考虑通过 HTTP 检索具有 gopher scheme 的 URI)。

Cookie 并不总是提供按 path 隔离。虽然网络层 协议不会将为一个 path 存储的 cookie 发送到另一个 path, 但一些用户代理通过非 HTTP API 公开 cookie,例如 HTML 的 document.cookie API。 因为其中一些用户代理(例如 Web 浏览器)不会隔离 从不同 path 获取的资源,所以从一个 path 检索到的资源可能 能够访问为另一个 path 存储的 cookie。

8.6. 弱完整性

Cookie 不为兄弟域(及其 子域)提供完整性保证。例如,考虑 foo.site.example 和 bar.site.example。 foo.site.example 服务器可以设置一个 Domain 属性为 “site.example”的 cookie(可能覆盖 bar.site.example 设置的现有 “site.example”cookie),而用户代理会在发往 bar.site.example 的 HTTP 请求中包含该 cookie。在最坏情况下,bar.site.example 将无法 将此 cookie 与其自己设置的 cookie 区分开来。foo.site.example 服务器可能能够利用这种能力对 bar.site.example 发起攻击。

即使 Set-Cookie 标头字段支持 Path 属性,Path 属性也不提供任何完整性保护,因为用户代理 会接受 Set-Cookie 标头字段中的任意 Path 属性。例如, 对 http://site.example/foo/bar 请求的 HTTP 响应可以设置 一个 Path 属性为“/qux”的 cookie。因此,服务器不应 在同一主机的不同 path 上运行彼此不信任的服务,同时又 使用 cookie 存储安全敏感信息。

主动网络攻击者还可以通过冒充来自 http://site.example/ 的响应并注入 Set-Cookie 标头字段, 将 cookie 注入发送给 https://site.example/ 的 Cookie 标头字段。 site.example 上的 HTTPS 服务器将无法将这些 cookie 与 它自己在 HTTPS 响应中设置的 cookie 区分开来。主动网络攻击者可能能够 利用这种能力对 site.example 发起攻击,即使 site.example 仅使用 HTTPS。

服务器可以通过加密并签名其 cookie 的内容,或通过使用 __Secure- 前缀命名 cookie,部分缓解这些攻击。 然而,使用密码学并不能完全缓解该问题,因为 攻击者可以在用户会话中重放其从真实 site.example 服务器接收到的 cookie,产生不可预测的结果。

最后,攻击者可能能够通过 存储大量 cookie 来强制用户代理删除 cookie。一旦用户代理达到其存储 限制,用户代理将被迫逐出一些 cookie。服务器不应 依赖用户代理保留 cookie。

8.7. 对 DNS 的依赖

Cookie 依赖域名系统(DNS)来保证安全。如果 DNS 被 部分或完全攻陷,cookie 协议可能无法提供 应用程序所需的安全属性。

8.8. SameSite Cookie

8.8.1. 纵深防御

“SameSite”cookie 在 strict 模式部署且客户端支持时, 可针对 CSRF 攻击提供健壮防御。 然而,谨慎的做法是确保此标记不是站点防御 CSRF 的全部手段, 因为 same-site 导航和提交当然可以与其他攻击向量结合执行, 例如 cross-site scripting 或滥用页面 重定向。

理解请求在何时以及如何被认为是 same-site,也 对正确设计使用 SameSite cookie 的站点非常重要。例如,如果对敏感页面发出一个 cross-site 顶级请求,该请求将被认为是 cross-site, 且 SameSite=Strict cookie 不会被发送;然而,该页面的 子资源请求是 same-site,并会接收 SameSite=Strict cookie。站点可以通过在初始页面请求未包含 适当 cookie 时返回错误,避免无意中允许访问这些子资源。

强烈鼓励开发者部署通常的服务器端 防御措施(CSRF token、确保“safe”HTTP 方法是幂等的等),以更充分地缓解 风险。

此外,[app-isolation] 中描述的客户端技术也可能 被证明能有效对抗 CSRF,并且当然值得与“SameSite” cookie 结合探索。

8.8.2. 顶级 导航

在“strict”模式下设置 SameSite 属性 可针对 CSRF 攻击提供健壮的纵深防御, 但除非站点开发者仔细确保其基于 cookie 的会话管理系统 能够合理处理顶级导航,否则可能会让用户感到困惑。

考虑这样一个场景:用户在 MegaCorp Inc 的 Webmail 提供商 https://site.example/ 阅读电子邮件。他们可能期望点击 电子邮件中的链接 https://projects.example/secret/project 后,能看到 其有权查看的秘密项目,但如果 https://projects.example 已将其会话 cookie 标记为 SameSite=Strict,则此 cross-site 导航不会随请求发送这些 cookie。https://projects.example 将渲染 404 错误以避免泄露秘密信息,而用户会 相当困惑。

开发者可以通过采用一种依赖不止一个而是两个 cookie 的会话管理 系统来避免这种困惑:一个在概念上授予“read”访问, 另一个授予“write”访问。后者可以标记为 SameSite=Strict, 其缺失会在执行任何非幂等操作前触发重新认证步骤。 前者可以标记为 SameSite=Lax,以 允许用户通过顶级导航访问数据,或标记为 SameSite=None,以允许在所有上下文中访问(包括 cross-site 嵌入上下文)。

8.8.3. 混搭应用和 小组件

SameSite 属性的 LaxStrict 值 不适合某些重要用例。特别要注意,旨在 嵌入 cross-site 上下文的内容(例如社交网络小组件或评论 服务)将无法访问 same-site cookie。这些情形中所需的 cookie 应标记为 SameSite=None, 以允许在 cross-site 上下文中访问。

同样,某些形式的 Single-Sign-On 可能需要 在 cross-site 上下文中进行基于 cookie 的身份验证;这些机制在使用 same-site cookie 时不会按预期工作,因此也需要 SameSite=None

8.8.4. 服务器控制

SameSite cookie 本身并不能解决 [RFC6265] 的第 7.1 节中概述的一般隐私关切。“SameSite” 属性由服务器设置,用于缓解服务器担心的某些类型 攻击的风险。用户并不参与此 决策。此外,还存在许多侧信道,即使在没有 cookie 的情况下也可能允许服务器 关联不同请求(例如,same-site 和 cross-site 请求之间的连接 和/或套接字池化)。

8.8.5. 重新加载导航

通过用户界面元素(例如工具栏上的 刷新按钮)触发的重新加载所发出的请求,只有在被重新加载的 document 最初是通过 same-site 请求导航到时,才是 same-site。这不同于 其他重新加载导航的处理方式;如果是顶级导航,它们始终是 same-site,因为 源 navigable 的活动 document 正是正在被 重新加载的 document。

这种对通过用户界面元素触发的重新加载的特殊处理, 避免了在用户发起的重新加载中发送 SameSite cookie, 如果这些 cookie 在原始导航中被保留未发送(即,如果初始导航是 cross-site)。如果重新加载导航反而被认为是 same-site,并 发送所有最初被保留未发送的 SameSite cookie,那么最初保留 cookie 不发送所带来的安全收益就会被抵消。这 尤其重要,因为在 cross-site 导航请求中被保留未发送的 SameSite cookie 缺失可能导致可见的站点破损,从而促使 用户触发重新加载。

例如,假设用户点击来自 https://attacker.example/ 指向 https://victim.example/ 的链接。这是一个 cross-site 请求,因此 SameSite=Strict cookie 会被保留不发送。假设这导致 https://victim.example/ 看起来 破损,因为该站点只有在请求中存在特定 SameSite cookie 时才显示其敏感内容。用户因站点意外破损而感到沮丧, 按下浏览器工具栏上的刷新。现在如果将 重新加载请求视为 same-site 并发送最初被保留的 SameSite cookie,就会违背最初保留它不发送的目的,因为 通过用户界面触发的重新加载导航可能会重放原始 (潜在恶意的)请求。因此,重新加载请求应被视为 cross-site,就像最初导航到该页面的请求一样。

由于针对非用户发起的重新加载发出的请求会附加所有 SameSite cookie,开发者在何时发起重新加载方面应谨慎而周到, 以避免 CSRF 攻击。例如,页面可以仅在初始请求中存在 CSRF token 时发起重新加载。

8.8.6. 使用 “unsafe”方法的顶级请求

第 5.6.7.1 节中描述的“Lax”执行模式允许 cookie 随 cross-site HTTP 请求发送,当且仅当它是使用“safe”HTTP 方法的 顶级导航。实现经验表明,将其作为默认行为很难应用, 因为某些站点可能依赖未显式指定 SameSite 属性的 cookie 被包含在使用“unsafe”HTTP 方法的 顶级 cross-site 请求中(这正是引入 SameSite 属性之前的情况)。

例如,登录流程的最后一步可能涉及对某个端点的 cross-site 顶级 POST 请求;该端点期望有一个最近创建的 cookie, 其中包含安全完成登录所需的事务状态信息。 对于这样的 cookie,“Lax”执行并不适合,因为它会导致 cookie 因 unsafe HTTP 请求方法而被排除,从而导致整个登录流程 发生不可恢复的失败。

第 5.6.7.2 节中描述的 “Lax-allowing-unsafe”执行模式保留了“Lax”执行的一些保护 (相较于“None”),同时仍允许最近创建的 cookie 随 unsafe 顶级请求进行 cross-site 发送。

作为“Lax”模式的更宽松变体,“Lax-allowing-unsafe” 模式 必然针对 CSRF 提供较少保护。最终,提供这种执行模式 应被视为一种临时的过渡措施, 以缓解默认采用“Lax”执行的过程。

8.9. 公共后缀列表

Cookie 的边界依赖站点的“registrable domain”,而后者又 依赖该域的 public suffix。

只要可能,用户代理应使用最新的 public suffix list, 例如 Mozilla 项目在 [PSL] 维护的列表。

未能这样做可能允许恶意或敏感 cookie 在 registrable domain 之间泄露。

9. IANA 注意事项

10. 参考文献

10.1. 规范性参考文献

van Kesteren, A., Denicola, D., Farolino, D., Hickson, I., Jägenstedt, P., and S. Pieters, "HTML - 现行标准", 无日期, <https://html.spec.whatwg.org/#dom-document-cookie>. WHATWG
[HTTP]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, , <https://www.rfc-editor.org/rfc/rfc9110>.
[RFC1034]
Mockapetris, P., "Domain names - concepts and facilities", STD 13, RFC 1034, DOI 10.17487/RFC1034, , <https://www.rfc-editor.org/rfc/rfc1034>.
[RFC1123]
Braden, R., Ed., "Requirements for Internet Hosts - Application and Support", STD 3, RFC 1123, DOI 10.17487/RFC1123, , <https://www.rfc-editor.org/rfc/rfc1123>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC4790]
Newman, C., Duerst, M., and A. Gulbrandsen, "Internet Application Protocol Collation Registry", RFC 4790, DOI 10.17487/RFC4790, , <https://www.rfc-editor.org/rfc/rfc4790>.
[RFC5234]
Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, DOI 10.17487/RFC5234, , <https://www.rfc-editor.org/rfc/rfc5234>.
[RFC5890]
Klensin, J., "Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework", RFC 5890, DOI 10.17487/RFC5890, , <https://www.rfc-editor.org/rfc/rfc5890>.
[RFC6454]
Barth, A., "The Web Origin Concept", RFC 6454, DOI 10.17487/RFC6454, , <https://www.rfc-editor.org/rfc/rfc6454>.
[RFC8126]
Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 8126, DOI 10.17487/RFC8126, , <https://www.rfc-editor.org/rfc/rfc8126>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[SAMESITE]
van Kesteren, A., Denicola, D., Farolino, D., Hickson, I., Jägenstedt, P., and S. Pieters, "HTML 现行标准", 无日期, <https://html.spec.whatwg.org/#same-site>. WHATWG
[USASCII]
American National Standards Institute, "Coded Character Set -- 7-bit American Standard Code for Information Interchange", ANSI X3.4, .

10.2. 资料性参考文献

[Aggarwal2010]
Aggarwal, G., Burzstein, E., Jackson, C., and D. Boneh, "An Analysis of Private Browsing Modes in Modern Browsers", , <http://www.usenix.org/events/sec10/tech/full_papers/Aggarwal.pdf>.
[app-isolation]
Chen, E., Bau, J., Reis, C., Barth, A., and C. Jackson, "App Isolation - Get the Security of Multiple Browsers with Just One", , <http://www.collinjackson.com/research/papers/appisolation.pdf>.
[CSRF]
Barth, A., Jackson, C., and J. Mitchell, "Robust Defenses for Cross-Site Request Forgery", DOI 10.1145/1455770.1455782, ISBN 978-1-59593-810-7, ACM CCS '08: Proceedings of the 15th ACM conference on Computer and communications security (pages 75-88), , <http://portal.acm.org/citation.cfm?id=1455770.1455782>.
[FETCH]
van Kesteren, A., "Fetch 现行标准", 无日期, <https://fetch.spec.whatwg.org/>. WHATWG
[HTML]
van Kesteren, A., Denicola, D., Farolino, D., Hickson, I., Jägenstedt, P., and S. Pieters, "HTML 现行标准", 无日期, <https://html.spec.whatwg.org/>. WHATWG
[HttpFieldNameRegistry]
"Hypertext Transfer Protocol (HTTP) Field Name Registry", 无日期, <https://www.iana.org/assignments/http-fields/>.
[prerendering]
Bentzel, C., "Chrome Prerendering", 无日期, <https://www.chromium.org/developers/design-documents/prerender>.
[PSL]
"Public Suffix List", 无日期, <https://publicsuffix.org/list/>.
[RFC2109]
Kristol, D. and L. Montulli, "HTTP State Management Mechanism", RFC 2109, DOI 10.17487/RFC2109, , <https://www.rfc-editor.org/rfc/rfc2109>.
[RFC3986]
Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, , <https://www.rfc-editor.org/rfc/rfc3986>.
[RFC4648]
Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, , <https://www.rfc-editor.org/rfc/rfc4648>.
[RFC6265]
Barth, A., "HTTP State Management Mechanism", RFC 6265, DOI 10.17487/RFC6265, , <https://www.rfc-editor.org/rfc/rfc6265>.
[RFC7034]
Ross, D. and T. Gondrom, "HTTP Header Field X-Frame-Options", RFC 7034, DOI 10.17487/RFC7034, , <https://www.rfc-editor.org/rfc/rfc7034>.
[RFC9113]
Thomson, M., Ed. and C. Benfield, Ed., "HTTP/2", RFC 9113, DOI 10.17487/RFC9113, , <https://www.rfc-editor.org/rfc/rfc9113>.
[RFC9114]
Bishop, M., Ed., "HTTP/3", RFC 9114, DOI 10.17487/RFC9114, , <https://www.rfc-editor.org/rfc/rfc9114>.
[SERVICE-WORKERS]
Archibald, J. and M. Kruisselbrink, "Service Workers", 无日期, <https://www.w3.org/TR/service-workers/>.
[TLS13]
Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, , <https://www.rfc-editor.org/rfc/rfc8446>.

附录 A. 相对于 RFC 6265 的变更

致谢

RFC 6265 由 Adam Barth 编写。本文档是 RFC 6265 的更新, 添加了特性,并使规范与当今部署的实际情况保持一致。 在这里,我们正站在巨人的肩膀上,因为 大部分文本仍然是 Adam 的。

感谢 Lily Chen 和 Steven Englehardt 两位荣誉编辑,他们为 改进此草案作出了重要贡献。

作者地址

Steven Bingler(编辑
Mike West(编辑
Google LLC
John Wilander(编辑
Apple, Inc