| 互联网草案 | Cookie:HTTP 状态管理机制 | 2026 年 6 月 |
| Bingler 等 | 2026 年 12 月 20 日过期 | [页] |
本文档定义了 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 日过期。¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
This document may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. The person(s) controlling the copyright in some of this material may not have granted the IETF Trust the right to allow modifications of such material outside the IETF Standards Process. Without obtaining an adequate license from the person(s) controlling the copyright in such materials, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process, except to format it for publication as an RFC or to translate it into languages other than English.¶
本文档定义 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 处理算法也不推荐现今使用的所有 语法和语义变体。在某些现有软件以重要方式不同于推荐协议时, 本文档包含一条说明该差异的注释。¶
本文档中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“NOT RECOMMENDED”、 “MAY”和“OPTIONAL”只有在像此处所示以全大写形式出现时,才应按照 BCP 14 [RFC2119] [RFC8174] 中的描述进行解释。¶
作为算法一部分以祈使语气表述的要求(例如“剥离 任何 前导空格字符”或“返回 false 并中止此算法”),应按照引入该算法时使用的 关键词(“MUST”、“SHOULD”、“MAY”等)的含义解释。¶
以算法或具体步骤表述的一致性要求可以用任何方式实现, 只要最终结果等价即可。特别地,本规范中定义的算法旨在 易于理解,而不旨在高性能。¶
本规范使用 [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(空白)。¶
术语“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 方法包括 GET、HEAD、
OPTIONS 和 TRACE,如
[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 的导航。¶
本节概述一种方式,使源服务器能够向 用户代理发送状态信息,并使用户代理能够将状态信息返回给源 服务器。¶
为了存储状态,源服务器在 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] 字符之外的任何内容。¶
使用 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¶
本节以足够详细的方式规定 Cookie 和 Set-Cookie 标头字段, 使精确实现这些要求的用户代理能够 与现有服务器互操作(即使这些服务器不符合第 4 节中描述的 行为良好配置文件)。¶
用户代理可以执行比本文规定更多的限制(例如, 由其 cookie 策略规定的限制,如第 7.2 节所述)。 但是,此类附加限制可能会降低用户 代理与现有服务器互操作的可能性。¶
本节定义用户代理用于处理 Cookie 和 Set-Cookie 标头字段的 特定子组件的一些算法。¶
如果两个 origin 满足 [SAMESITE] 中定义的“same site”准则,则它们是 same-site。 如果以下准则为真,则请求是“same-site”:¶
该请求不是通过用户界面元素触发的 重新加载导航的结果(由 用户代理定义;例如,用户点击工具栏上的刷新按钮触发的请求)。¶
请求的 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 类型计算,如以下小节所述:¶
用户代理地址栏中显示的 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”:¶
令 top-document 为
document 的 navigable 的
top-level traversable 中的活动 document。¶
如果设置了 top-document 的
sandboxed origin browsing context flag,则令 top-origin 为
top-document 的 URI 的 origin;否则为 top-document 的
origin。¶
令 documents 为一个列表,由
document 的 inclusive ancestor navigables 的活动 document
组成。¶
对 documents 中的每个 item:¶
返回 top-origin。¶
注:此算法仅在从
top-document 到 document 的整个 document 链
全部处于活动状态时适用。¶
Worker 驱动的请求不像 document 驱动的 请求那样清晰, 因为顶级 traversable 与 worker 之间没有明确链接。 对于 Service Workers [SERVICE-WORKERS] 尤其如此,它们可能 在后台执行代码,而没有任何可见 document。¶
Service Workers 更复杂,因为它们作为一个 完全独立的 执行上下文运行,并且只与注册它们的 Document 有间接关系。¶
用户代理处理 Service Workers 的方式可能不同,但 用户代理应 匹配 [SERVICE-WORKERS] 规范。¶
用户代理关于 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=/¶
用户代理存储每个 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:¶
如果 cookie-name 为空且 cookie-value 为空,则中止此 算法并 完全忽略该 cookie。¶
如果 cookie-name 或 cookie-value 包含 %x00-08 / %x0A-1F / %x7F 字符(不包括 HTAB 的 CTL 字符), 则中止此算法并完全忽略该 cookie。¶
如果 cookie-name 和 cookie-value 的长度之和超过 4096 个八位组,则中止此算法并完全忽略该 cookie。¶
创建一个新 cookie,其 name 为 cookie-name,value 为 cookie-value。将 creation-time 和 last-access-time 设置为当前日期和时间。¶
如果 cookie-attribute-list 包含一个 attribute-name 为“Max-Age”的属性:¶
将 cookie 的 persistent-flag 设置为 true。¶
将 cookie 的 expiry-time 设置为 cookie-attribute-list 中最后一个 attribute-name 为 “Max-Age”的属性的 attribute-value。¶
否则,如果 cookie-attribute-list 包含一个 attribute-name 为“Expires”的属性(且不包含 attribute-name 为“Max-Age”的属性):¶
将 cookie 的 persistent-flag 设置为 true。¶
将 cookie 的 expiry-time 设置为 cookie-attribute-list 中最后一个 attribute-name 为 “Expires”的属性的 attribute-value。¶
否则:¶
如果 cookie-attribute-list 包含一个 attribute-name 为“Domain”的属性:¶
令 domain-attribute 为 cookie-attribute-list 中最后一个同时具有 attribute-name 为“Domain”且 attribute-value 长度不超过 1024 个八位组的属性的 attribute-value。(请注意,前导 %x2E (“.”)若存在则会被忽略,即使该字符并不 被允许。)¶
否则:¶
令 domain-attribute 为空字符串。¶
如果 domain-attribute 包含不属于 CHAR 的字符,则中止 此算法并完全忽略该 cookie。¶
如果用户代理被配置为拒绝“public suffixes”,且 domain-attribute 是 public suffix:¶
令 request-host-canonical 为规范化后的 request-host。¶
如果 request-host 未能规范化,则中止 此算法并 完全忽略该 cookie。¶
如果 domain-attribute 与 request-host-canonical 完全相同:¶
令 domain-attribute 为空 字符串。¶
否则:¶
中止此算法并完全忽略该 cookie。¶
注:此步骤防止 attacker.example 通过设置一个 Domain 属性为“example”的 cookie
来破坏 site.example 的完整性。¶
如果 domain-attribute 非空:¶
否则:¶
如果 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。¶
如果 cookie-attribute-list 包含一个 attribute-name 为“Secure”的属性,则将 cookie 的 secure-only-flag 设置为 true。 否则,将 cookie 的 secure-only-flag 设置为 false。¶
如果 request-uri 不表示一个“secure”连接(由 用户代理定义),且 cookie 的 secure-only-flag 为 true,则中止这些 步骤并完全忽略该 cookie。¶
如果 cookie-attribute-list 包含一个 attribute-name 为“HttpOnly”的属性,则将 cookie 的 http-only-flag 设置为 true。 否则,将 cookie 的 http-only-flag 设置为 false。¶
如果 cookie 是从“non-HTTP”API 接收的,且 cookie 的 http-only-flag 为 true,则中止此算法并完全忽略该 cookie。¶
如果 cookie 的 secure-only-flag 为 false,且 request-uri 不表示一个“secure”连接,那么如果 cookie 存储包含一个或多个满足 以下所有准则的 cookie,则中止此算法并完全忽略 该 cookie:¶
其 name 与新创建的 cookie 的 name 匹配。¶
其 secure-only-flag 为 true。¶
其 domain domain-matches(见第 5.1.3 节)新创建 cookie 的 domain,或反之亦然。¶
新创建 cookie 的 path path-matches 现有 cookie 的 path。¶
注:path 比较不是对称的,只确保 新创建的非安全 cookie 不会覆盖现有的安全 cookie,从而对 cookie-fixing 攻击提供一定缓解。也就是说, 给定一个名为 'a'、path 为 '/login' 的现有安全 cookie, 可以为 path '/' 或 '/foo' 设置一个名为 'a' 的 非安全 cookie,但不能为 path '/login' 或 '/login/en' 设置。¶
如果 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”。¶
如果 cookie 的 same-site-flag 不是“None”:¶
如果 cookie 是从“non-HTTP”API 接收的,且 该 API 是从一个 navigable 的活动 document 调用的,而其“site for cookies” 与 top-level origin 不是 same-site,则中止此算法并 完全忽略新创建的 cookie。¶
如果 cookie 是从“same-site”请求接收的 (如第 5.2 节所定义),则跳过 剩余子步骤并继续 处理该 cookie。¶
如果 cookie 是从正在导航
top-level traversable [HTML]
的请求接收的
(例如,如果请求的“reserved
client”为 null,或是一个其“target browsing
context”的 navigable 为 top-level traversable 的环境),则跳过
剩余子步骤并继续处理该 cookie。¶
注:顶级导航可以创建任何 SameSite
值的 cookie,即使该新 cookie 若在导航前已经存在也不会随
该请求一起发送。¶
中止此算法并完全忽略新创建的 cookie。¶
如果 cookie 的“same-site-flag”为“None”,则中止此算法并 完全忽略该 cookie,除非 cookie 的 secure-only-flag 为 true。¶
如果 cookie-name 以大小写不敏感方式匹配字符串 “__Secure-”开头,则中止此算法并完全忽略该 cookie,除非 cookie 的 secure-only-flag 为 true。¶
如果 cookie-name 以大小写不敏感方式匹配字符串 “__Host-”开头,则中止此算法并完全忽略该 cookie,除非 cookie 满足以下所有准则:¶
如果 cookie-name 为空,并且以下任一 条件为 true,则中止此算法并完全忽略该 cookie:¶
如果 cookie 存储包含一个与新创建 cookie 的 name、domain、 host-only-flag 和 path 相同的 cookie:¶
令 old-cookie 为与新创建 cookie 具有相同 name、domain、 host-only-flag 和 path 的现有 cookie。(请注意,此 算法维持以下不变量:至多存在一个这样的 cookie。)¶
如果新创建的 cookie 是从 “non-HTTP”API 接收的,且 old-cookie 的 http-only-flag 为 true,则中止此算法并 完全忽略新创建的 cookie。¶
更新新创建 cookie 的 creation-time 以匹配 old-cookie 的 creation-time。¶
从 cookie 存储中移除 old-cookie。¶
将新创建的 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:¶
Expired cookies。¶
secure-only-flag 为 false,且与超过预定数量的 其他 cookie 共享 domain 字段的 cookie。¶
与超过预定数量的 其他 cookie 共享 domain 字段的 cookie。¶
所有 cookie。¶
如果两个 cookie 具有相同的移除优先级,则用户代理必须先逐出 last-access-time 最早的 cookie。¶
当“the current session is over”(由用户代理定义)时,用户 代理必须从 cookie 存储中移除所有 persistent-flag 设置为 false 的 cookie。¶
本节定义如何以 cookie-string 的形式 从 cookie 存储中检索 cookie。“retrieval”是任何需要生成 cookie-string 的事件。例如,为了构建 HTTP 请求的 Cookie 标头字段,可能会发生 retrieval;或者为了从提供 cookie 访问能力的 “non-HTTP”API 调用返回 cookie-string,可能需要 retrieval。retrieval 具有相关联的 URI、same-site 状态和类型, 它们根据 retrieval 类型在下文定义。¶
用户代理可以实现可用于访问 已存储 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”。¶
给定一个 cookie 存储和一次 retrieval,以下算法 从给定 cookie 存储返回 cookie-string。¶
令 retrieval-host-canonical 为 retrieval 的 URI 的 规范化 host。¶
如果 retrieval 的 URI 的 host 未能 规范化,则中止此 算法。¶
令 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,除非满足以下所有 条件:¶
用户代理应按以下顺序排序 cookie-list:¶
path 较长的 cookie 列在 path 较短的 cookie 之前。¶
在 path 字段等长的 cookie 中, creation-time 较早的 cookie 列在 creation-time 较晚的 cookie 之前。¶
注:并非所有用户代理都按此顺序排序 cookie-list,但此顺序 反映了本文档编写时的常见实践,并且历史上 曾有服务器(错误地)依赖此顺序。¶
将 cookie-list 中每个 cookie 的 last-access-time 更新为 当前日期和时间。¶
按顺序处理 cookie-list 中的每个 cookie, 将 cookie-list 序列化为 cookie-string:¶
实际的用户代理实现对它们可以存储的 cookie 数量和大小有限制。通用用户代理应提供以下 最低能力:¶
用户代理可以限制其存储的 cookie 最大数量,并且可以在任何时候逐出 任意 cookie(无论是应用户请求,还是由于 实现限制)。¶
请注意,对 cookie 最大数量的限制也会限制 已存储 cookie 的总大小,这是由于 第 5.6 节中必须强制执行的长度限制。¶
服务器应使用尽可能少且尽可能小的 cookie,以避免达到 这些实现限制,最大限度减少因 Cookie 标头字段包含在每个请求中而产生的网络带宽消耗,并避免达到 服务器标头字段限制(见第 4.2.1 节)。¶
如果用户代理由于可能在任何时候逐出任意 cookie 而未能在 Cookie 标头字段中返回一个或多个 cookie,则服务器应优雅降级。¶
Cookie 的主要隐私风险是其关联用户活动的能力。这 可能发生在单个站点上,但当活动被跨不同的、 看似无关的网站跟踪以构建用户画像时,问题最为严重。¶
随着时间推移,这种能力(在 [RFC2109] 及其所有后续规范中均被明确警告反对) 已因各种原因被广泛使用,包括:¶
虽然并非每种 cookie 使用都一定会带来隐私问题,但其潜在的滥用 已成为 Internet 社区和更广泛社会中的普遍关切。为回应这些 关切,用户代理 已经以各种方式主动限制 cookie 功能(如先前规范所允许和鼓励的那样), 同时避免破坏它们认为有益于 Web 健康的功能。¶
现在宣称应使用哪些具体机制来缓解 cookie 的隐私影响还为时过早; 用户代理当前持续改变其处理方式,最好被描述为能够为 最终共识提供输入的实验。¶
相反,本文档描述了有限的、通用的缓解措施,用于应对 与 cookie 相关的隐私风险,这些措施在本文写作时已得到广泛部署。预计实现 将继续进行实验,并随着时间推移对 cookie 施加更严格、更明确的限制。 本文档的未来版本可能会根据部署经验将这些机制编纂成规范。 如果当前依赖 cookie 的功能能够由单独的、有针对性的 机制支持,那么它们可能会被记录在单独的规范中,并且对 cookie 的更严格限制 可能变得可行。¶
请注意,cookie 并不是唯一可用于跨站点跟踪用户的机制, 因此,虽然这些缓解措施对于改善 Web 隐私是必要的, 但仅靠它们本身并不足够。¶
用户代理应向用户提供一种机制,用于管理 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]。¶
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。¶
除非通过安全通道(例如 TLS [TLS13])发送,否则 Cookie 和 Set-Cookie 标头字段中的信息会以明文传输。¶
服务器在将 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。¶
服务器通常不会直接在 cookie 中存储会话信息(在那里它可能 暴露给攻击者或被攻击者重放),而是在 cookie 中存储一个 nonce(或“session identifier”)。当服务器收到 带有 nonce 的 HTTP 请求时,服务器可以使用该 nonce 作为键, 查找与该 cookie 关联的状态信息。¶
使用会话标识符 cookie 可以限制攻击者在获知 cookie 内容时能够造成的损害,因为 nonce 只对 与服务器交互有用(不同于非 nonce 的 cookie 内容,后者本身 可能是敏感的)。此外,使用单个 nonce 可防止攻击者将 与服务器两次交互中的 cookie 内容“splicing”在一起,这 可能导致服务器表现出意外行为。¶
使用会话标识符并非没有风险。例如,服务器应 注意避免“session fixation”漏洞。session fixation 攻击 分三步进行。首先,攻击者将一个会话标识符 从其用户代理移植到受害者的用户代理。其次,受害者使用 该会话标识符与服务器交互,可能会将 用户的凭据或机密信息赋予该 会话标识符。第三,攻击者使用该会话标识符直接与服务器 交互,可能获得用户的授权或机密信息。¶
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。¶
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。¶
添加 same-site 概念和 SameSite 属性。 (第 5.2 节和第 4.1.2.7 节)¶
引入 cookie 前缀,并禁止无名 cookie 设置 会模仿 cookie 前缀的值。(第 4.1.3 节和 第 5.7 节)¶
禁止非安全 origin 设置带有
Secure 标志的 cookie,或
覆盖带有此标志的 cookie。(第
5.7 节)¶
改进 cookie 语法¶
通过更新 path-value 和 extension-av 语法处理 errata 3444, 通过更新 day-of-month、year 和 time 语法处理 errata 4148,并通过添加所请求的注释 处理 errata 3663。(第 4.1 节和第 5.1.4 节)¶