互联网工程任务组 (IETF) A. Barth
请求评议:6265 U.C. Berkeley
废止:2965 2011年4月
类别:标准轨道
ISSN: 2070-1721

HTTP 状态管理机制


摘要

本文档定义了 HTTP 的 Cookie 和 Set-Cookie 首部字段。HTTP 服务器可以使用这些首部字段在 HTTP 用户代理端存储状态(称为 cookie),使服务器能够在主要无状态的 HTTP 协议上维持有状态的会话。尽管 cookies 在历史上存在许多降低其安全性和隐私性的不完美之处,但 Cookie 与 Set-Cookie 首部在互联网上被广泛使用。本文档废止了 RFC 2965。

本备忘录的状态

这是一个互联网标准轨道文档。

本文件是互联网工程任务组(IETF)的成果,代表 IETF 社区的共识。它已获得公开评审,并由互联网工程指导小组(IESG)批准发布。关于互联网标准的更多信息请参见 RFC 5741 第2节

关于本文档当前状态、勘误及如何提供反馈的信息,可从 http://www.rfc-editor.org/info/rfc6265 获取。

Copyright Notice

Copyright (c) 2011 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 (http://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 Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified 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.

1. 引言

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

尽管表面上很简单,cookie 具有许多复杂性。例如,服务器在发送 cookie 给用户代理时指示每个 cookie 的作用域。该作用域指明用户代理在多长时间内应返回该 cookie、应将 cookie 返回给哪些服务器,以及该 cookie 适用于哪些 URI 方案。

出于历史原因,cookie 存在若干降低其安全性和隐私性的缺陷。例如,服务器可以指示某个 cookie 仅用于“secure”(安全)连接,但 Secure 属性并不能在存在主动网络攻击者时提供完整性保护。同样,某个主机的 cookie 会在该主机的所有端口间共享,尽管 Web 浏览器通常采用的“同源策略”会将通过不同端口检索的内容隔离开来。

本规范面向两个受众:cookie 生成服务器的开发者和 cookie 消费用户代理的开发者。

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

用户代理 必须 实现 第 5 节 中定义的较宽松的处理规则,以便与不遵从第 4 节所述良性配置文件的现有服务器最大程度地互操作。

本文档规定了这些首部在互联网上实际使用时的语法和语义。特别地,本文件并未创建超出当前使用范围的新语法或语义。第 4 节 中提供的生成 cookie 的建议代表当前服务器行为的首选子集,即便第 5 节 中的更宽松的 cookie 处理算法也并不建议采用现在存在的所有语法和语义变体。对于某些现有软件在显著方面与建议协议不同的情况,本文档包含注释以解释差异。

在本文档发布之前,至少存在三种关于 cookie 的描述:所谓的“网景 cookie 规范” [Netscape]、RFC 2109 [RFC2109] 和 RFC 2965 [RFC2965]。然而,这些文档均未描述 Cookie 和 Set-Cookie 首部在互联网上的实际使用情况(历史背景见 [Kri2001])。关于此前 IETF 对 HTTP 状态管理机制的规范,本文档请求执行以下操作:

  1. [RFC2109] 的状态改为 Historic(它已被 [RFC2965] 弃用)。
  2. [RFC2965] 的状态改为 Historic。
  3. 指出 [RFC2965] 已被本文档弃用。

特别是,在将 RFC 2965 标记为 Historic 并以本文档将其弃用后,本文件弃用了 Cookie2 和 Set-Cookie2 首部字段的使用。

2. 约定

2.1. 一致性准则

本文档中的关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY" 和 "OPTIONAL" 应按照 [RFC2119] 的定义进行解释。

以算法形式表述的强制性要求(例如 "剥离任何前导空格字符" 或 "返回 false 并中止这些步骤")在引入该算法时使用的关键词(如 "MUST"、"SHOULD"、"MAY" 等)具有相应的含义。

以算法或具体步骤表述的一致性要求可以通过任何方式实现,只要最终结果等效。尤其是,规范中定义的算法旨在便于理解,而非关注性能。

2.2. 语法表示法

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

下列核心规则按引用包含自 [RFC5234] 的附录 B.1:ALPHA(字母)、CR(回车)、CRLF(CR LF)、CTL(控制字符)、DIGIT(十进制 0-9)、DQUOTE(双引号)、HEXDIG(十六进制 0-9/A-F/a-f)、LF(换行)、NUL(空字节)、OCTET(除 NUL 外的任意 8 位字节序列)、SP(空格)、HTAB(水平制表)、CHAR(任意 [USASCII] 字符)、VCHAR(任意可见 [USASCII] 字符)和 WSP(空白字符)。

规则 OWS(可选空白)用于表示零个或多个线性空白字符 可以 出现的位置:

OWS            = *( [ obs-fold ] WSP )
                 ; "optional" whitespace
obs-fold       = CRLF
          

OWS 建议 要么不产生,要么仅作为单个 SP 字符产生。

2.3. 术语

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

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

术语 request-uri 的定义见 RFC2616 第 5.1.2 节

当且仅当两序列在 [RFC4790] 中定义的 i;ascii-casemap 排序下等效时,称这两序列在不区分大小写的情况下匹配。

术语 string 意味着一序列非 NUL 八位字节。

3. 概述

本节概述了源服务器如何向用户代理发送状态信息,以及用户代理如何将该状态信息返回给源服务器。

为了存储状态,源服务器在 HTTP 响应中包含 Set-Cookie 首部。在随后发送的请求中,用户代理会向源服务器返回 Cookie 请求首部。Cookie 首部包含用户代理先前在 Set-Cookie 首部中接收的 cookies。源服务器可以选择忽略 Cookie 首部,或将其内容用于应用定义的目的。

源服务器 可以 在任何响应中发送 Set-Cookie 响应首部。用户代理 可以 忽略包含在 100 级响应中的 Set-Cookie 首部,但 必须 处理包含在其他响应(包括 400 和 500 级响应)中的 Set-Cookie 首部。源服务器可以在单个响应中包含多个 Set-Cookie 首部字段。Cookie 或 Set-Cookie 首部的存在并不妨碍 HTTP 缓存存储和重用响应。

源服务器 不应 将多个 Set-Cookie 首部合并为单个首部。通常的 HTTP 首部折叠机制(即 [RFC2616] 中定义的)可能会改变 Set-Cookie 首部的语义,因为 %x2C (",") 字符在 Set-Cookie 中的使用与这种折叠冲突。

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 返回给 example.com 的每个路径和每个子域。

== Server -> User Agent ==

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

== 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=example.com
          

== User Agent -> Server ==

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

注意上面的 Cookie 首部包含两个 cookie,一个名为 SID,另一个名为 lang。如果服务器希望用户代理在多个“会话”(例如用户代理重启)之间保留 cookie,服务器可以在 Expires 属性中指定过期日期。注意,如果用户代理的 cookie 存储超过配额或用户手动删除了服务器的 cookie,用户代理可能会在过期日期之前删除该 cookie。

== Server -> User Agent ==

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

== User Agent -> Server ==

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

最后,要删除 cookie,服务器返回一个 Expires 在过去的 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
          

4. Server Requirements

本节描述了 Cookie 与 Set-Cookie 首部的良性配置文件的语法与语义。

5. User Agent Requirements

本节详尽规定了 Cookie 与 Set-Cookie 首部,以便精确实现这些要求的用户代理能够与现有服务器互操作(即便这些服务器不遵从第 4 节 中描述的良性配置文件)。

用户代理可以强制比此处更严格的限制(例如出于提高安全性的目的);然而实验表明,这种严格性会降低用户代理与现有服务器互操作的可能性。

5.1. Subcomponent Algorithms

本节定义了一些用户代理用于处理 Cookie 与 Set-Cookie 首部特定子组件的算法。

5.3. Storage Model

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

当用户代理从 request-uri 接收了一个名称为 cookie-name、值为 cookie-value、属性为 cookie-attribute-list 的 cookie 时,用户代理 MUST 按如下方式处理该 cookie:

  1. 用户代理 MAY 完全忽略接收到的 cookie。例如,用户代理可能希望阻止从“第三方”响应接收 cookie,或可能不希望存储超过某个大小的 cookie。
  2. 创建一个新 cookie,名称为 cookie-name,值为 cookie-value。将 creation-time 与 last-access-time 设为当前日期时间。
  3. 如果 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" 的属性(且不包含 "Max-Age"):
    • 将 cookie 的 persistent-flag 设为 true。
    • 将 cookie 的 expiry-time 设为 cookie-attribute-list 中最后一个 attribute-name 为 "Expires" 的属性的 attribute-value。
    否则:
    • 将 cookie 的 persistent-flag 设为 false。
    • 将 cookie 的 expiry-time 设为最新可表示的日期。
  4. 如果 cookie-attribute-list 包含 attribute-name 为 "Domain" 的属性:
    • 令 domain-attribute 为 cookie-attribute-list 中最后一个 attribute-name 为 "Domain" 的属性的 attribute-value。
    否则:
    • 令 domain-attribute 为空字符串。
  5. 如果用户代理被配置为拒绝“公共后缀”且 domain-attribute 是公共后缀:
    • 如果 domain-attribute 与规范化的 request-host 相同:
      • 令 domain-attribute 为空字符串。
      否则:
      • 完全忽略该 cookie 并中止这些步骤。
    • 注:公共后缀是由公共注册机构控制的域,例如 "com"、"co.uk" 与 "pvt.k12.wy.us"。此步骤对于防止 attacker.com 通过设置 Domain 属性为 "com" 来破坏 example.com 的完整性是必要的。公共后缀集合随时间变化;如果可行,用户代理 SHOULD 使用最新的公共后缀列表,例如 Mozilla 项目维护的 <http://publicsuffix.org/>。
  6. 如果 domain-attribute 非空:
    • 如果 规范化的 request-host 不与 domain-attribute domain-match:
      • 完全忽略该 cookie 并中止这些步骤。
      否则:
      • 将 cookie 的 host-only-flag 设为 false。
      • 将 cookie 的 domain 设为 domain-attribute。
    否则:
    • 将 cookie 的 host-only-flag 设为 true。
    • 将 cookie 的 domain 设为 规范化的 request-host。
  7. 如果 cookie-attribute-list 包含 attribute-name 为 "Path" 的属性,则将 cookie 的 path 设为 cookie-attribute-list 中最后一个 attribute-name 为 "Path" 的属性的 attribute-value。否则,将 cookie 的 path 设为 request-uri 的 default-path。
  8. 如果 cookie-attribute-list 包含 attribute-name 为 "Secure",则将 cookie 的 secure-only-flag 设为 true。否则将其设为 false。
  9. 如果 cookie-attribute-list 包含 attribute-name 为 "HttpOnly",则将 cookie 的 http-only-flag 设为 true。否则将其设为 false。
  10. 如果 cookie 是从“非 HTTP”API 接收的,且 cookie 的 http-only-flag 被设置,则中止这些步骤并完全忽略该 cookie。
  11. 如果 cookie 存储中存在与新创建 cookie 具有相同 name、domain 与 path 的 cookie:
    1. 令 old-cookie 为存储中与新创建 cookie 具有相同 name、domain 与 path 的现存 cookie。(注意此算法保持不变性,即至多存在一个此类 cookie。)
    2. 如果新创建的 cookie 是从“非 HTTP”API 接收的且 old-cookie 的 http-only-flag 被设置,则中止这些步骤并完全忽略新创建的 cookie。
    3. 将新创建 cookie 的 creation-time 更新为 old-cookie 的 creation-time。
    4. 从 cookie 存储中移除 old-cookie。
  12. 将新创建的 cookie 插入 cookie 存储。

如果 cookie 的过期日期在过去,则该 cookie 被视为“已过期”。

如果 cookie 存储中存在过期 cookie,用户代理 MUST 驱逐所有过期 cookie。

在任意时刻,如果共享相同 domain 字段的 cookie 数量超过实现定义的上限(例如 50 个 cookie),用户代理 MAY“移除过多的 cookie”。

在任意时刻,如果 cookie 存储超过某个预定上限(例如 3000 个 cookie),用户代理 MAY“移除过多的 cookie”。

当用户代理从 cookie 存储中移除过多的 cookie 时,用户代理 MUST 按以下优先顺序驱逐 cookie:

  1. 已过期的 cookie。
  2. 与超过预定数量其他 cookies 共享 domain 字段的 cookies。
  3. 所有 cookies。

如果两个 cookie 具有相同的移除优先级,用户代理 MUST 先驱逐 last-access 时间最早的 cookie。

当“当前会话结束”(由用户代理定义)时,用户代理 MUST 从 cookie 存储中移除所有 persistent-flag 为 false 的 cookies。

6. 实现注意事项

6.1. 限制

实际的用户代理实现对于它们能存储的 cookie 的数量和大小存在限制。一般用途的用户代理 应当 提供以下最低能力:

  • 每个 cookie 至少 4096 字节(按 cookie 的 name、value 与 attributes 长度之和计算)。
  • 每个域名至少 50 个 cookie。
  • 总计至少 3000 个 cookie。

服务器 应当 尽量使用更少且更小的 cookie,以避免达到这些实现限制,并减少由于在每个请求中包含 Cookie 首部而产生的网络带宽消耗。

服务器 应当 在用户代理未能在 Cookie 首部中返回一个或多个 cookie 时能够优雅降级,因为用户可能会随时根据用户的指令逐出任意 cookie。

6.2. 应用编程接口

Cookie 与 Set-Cookie 首部使用如此晦涩语法的一个原因是,许多平台(无论服务器端还是用户代理端)都为 cookie 提供基于字符串的应用编程接口(API),要求应用层程序员生成和解析 Cookie 与 Set-Cookie 首部使用的语法。许多程序员在这方面做得不正确,导致互操作性问题。

与其提供基于字符串的 cookie API,平台更适合提供语义更强的 API。本文档不建议具体的 API 设计,但接受抽象的“Date”对象而不是序列化的日期字符串有明显好处。

6.3. IDNA 依赖与迁移

IDNA2008 [RFC5890] 已取代 IDNA2003 [RFC3490]。 然而,两者规范之间存在差异,因此对以其中一种规范注册的域名标签的处理(例如转换)可能会有所不同。在一段过渡期内,基于 IDNA2003 的域名标签仍将存在于互联网上。用户代理 应当 实现 IDNA2008 [RFC5890] ,并且 可以 实现 [UTS46][RFC5895] 来促进它们的 IDNA 过渡。如果用户代理没有实现 IDNA2008,则该用户代理 必须 实现 IDNA2003 [RFC3490]

7. 隐私注意事项

Cookies 常因允许服务器跟踪用户而受到批评。例如,一些“网页分析”公司使用 cookie 来识别用户何时返回某个网站或访问另一个网站。尽管 cookie 并不是服务器跨 HTTP 请求跟踪用户的唯一机制,但 cookie 便于跟踪,因为它们在用户代理会话之间是持久的,并且可以在主机之间共享。

7.1. 第三方 Cookie

尤其令人担忧的是所谓的“第三方” cookie。在呈现 HTML 文档时,用户代理经常会请求来自其他服务器的资源(例如广告网络)。即使用户从未直接访问该第三方服务器,这些第三方服务器也可以使用 cookie 来跟踪用户。例如,如果用户访问了包含第三方内容的网站,之后又访问包含相同第三方内容的另一个网站,则该第三方可以在两者之间跟踪该用户。

一些用户代理会限制第三方 cookie 的行为。例如,有些用户代理会拒绝在第三方请求中发送 Cookie 首部;另一些则拒绝处理对第三方请求的响应中的 Set-Cookie 首部。用户代理在第三方 cookie 策略上差异很大。本文档允许用户代理在第三方 cookie 策略上有很大的试验空间,以平衡用户的隐私与兼容性需求。然而,本文档并不支持任何特定的第三方 cookie 策略。

如果服务器尝试绕过限制来跟踪用户,第三方 cookie 阻止策略通常在实现其隐私目标方面效果有限。特别地,两个协作的服务器往往可以在不使用 cookie 的情况下通过将识别信息注入动态 URL 来跟踪用户。

7.2. 用户控制

用户代理 应当 为用户提供管理 cookie 存储的机制。例如,用户代理可允许用户删除在指定时间段内接收的所有 cookie,或删除与特定域相关的所有 cookie。此外,许多用户代理包含可供用户检查其 cookie 存储的用户界面元素。

用户代理 应当 为用户提供禁用 cookie 的机制。当 cookie 被禁用时,用户代理 必须不 在出站 HTTP 请求中包含 Cookie 首部,并且用户代理 必须不 处理入站 HTTP 响应中的 Set-Cookie 首部。

一些用户代理提供阻止跨会话持久存储 cookie 的选项。当这样配置时,用户代理 必须 将所有接收的 cookie 视为其 persistent-flag 被设置为 false。某些流行的用户代理通过“私密浏览”模式暴露此功能 [Aggarwal2010]

一些用户代理允许用户批准对 cookie 存储的单次写入。在许多常见使用场景中,这些控制会产生大量提示。然而,一些注重隐私的用户仍然觉得这些控制有用。

7.3. 过期日期

尽管服务器可以将 cookie 的过期日期设置为非常遥远的将来,但大多数用户代理并不会真正保留 cookie 数十年。服务器 应当 通过根据 cookie 的用途选择合理的过期期来促进用户隐私,而不是任意选择很长的过期期。例如,一个典型的会话标识符将合理地设置为两周后过期。

8. 安全性注意事项

8.1. 概述

Cookies 存在若干安全陷阱。本节概述其中一些较突出的议题。

特别地,cookies 鼓励开发者依赖环境权限(ambient authority)进行认证,从而常常容易受到诸如跨站请求伪造(cross-site request forgery)等攻击的影响 [CSRF]。此外,在 cookie 中存储会话标识符时,开发者常常会产生会话固定(session fixation)漏洞。

传输层加密(如 HTTPS)不足以防止网络攻击者获取或篡改受害者的 cookies,因为 cookie 协议本身存在各种漏洞(参见下文的“弱机密性”与“弱完整性”部分)。此外,默认情况下,即使与 HTTPS 配合使用,cookies 也不能为网络攻击者提供机密性或完整性保护。

8.2. 环境权限

使用 cookies 进行用户认证的服务器可能会遭受安全漏洞,因为某些用户代理允许远端方从用户代理发起 HTTP 请求(例如,通过 HTTP 重定向或 HTML 表单)。在发起这些请求时,用户代理会附带 cookies,即使远端方不知道这些 cookie 的内容,这可能会让远端方在毫不知情的服务器上行使权限。

虽然此安全问题有若干不同名称(如跨站请求伪造、confused deputy),问题的根源在于 cookies 属于一种环境权限。cookies 鼓励服务器操作者将指定(以 URL 形式)与授权(以 cookie 形式)分离。因此,用户代理可能会为攻击者指定的资源提供授权,这可能导致服务器或其客户端将攻击者指定的操作视为用户已授权的操作。

服务器操作者可能希望考虑通过将指定与授权纠缠(entangle)来替代使用 cookies 进行授权的做法,即将 URL 视为 capability。与其将秘密存储在 cookies 中,这种方法将秘密存储在 URL 中,要求远端实体提供该秘密本身。尽管该方法并非万灵药,但在审慎应用下可以带来更健壮的安全性。

8.3. 明文传输

除非通过安全通道(例如 TLS)发送,否则 Cookie 与 Set-Cookie 首部中的信息以明文传输。

  1. 这些首部中传递的所有敏感信息都将暴露给窃听者。
  2. 恶意中间人可能在任一方向篡改这些首部,结果不可预测。
  3. 恶意客户端可能在发送前篡改 Cookie 首部,结果不可预测。

服务器 应当 在将 cookie 传输给用户代理时对 cookie 内容进行加密和签名(使用服务器希望的任意格式),即使在通过安全通道发送时也是如此。然而,加密与签名 cookie 内容并不能阻止攻击者将 cookie 从一个用户代理移植到另一个用户代理,也不能阻止攻击者在稍后重放该 cookie。

除了对每个 cookie 的内容进行加密与签名之外,需要更高安全级别的服务器 应当 仅在安全通道上使用 Cookie 与 Set-Cookie 首部。在通过安全通道使用 cookies 时,服务器 应当 为每个 cookie 设置 Secure 属性(见 第 4.1.2.5 节)。如果服务器未设置 Secure 属性,那么安全通道提供的保护在很大程度上将变得无效。

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

8.4. 会话标识符

服务器通常将 nonce(或“会话标识符”)存储在 cookie 中,而不是直接在 cookie 中存储会话信息(以避免被攻击者暴露或重放)。当服务器收到带有 nonce 的 HTTP 请求时,服务器可以使用该 nonce 作为键来查找与 cookie 关联的状态信息。

使用会话标识符 cookie 在攻击者获知 cookie 内容时能够限制攻击者造成的损害,因为 nonce 仅用于与服务器交互(与可能本身敏感的非 nonce cookie 内容不同)。此外,使用单个 nonce 可以防止攻击者“拼接”两次与服务器交互中的 cookie 内容,从而避免导致服务器异常行为。

使用会话标识符并非没有风险。例如,服务器 应当 注意避免“会话固定”漏洞。会话固定攻击通常包含三个步骤。首先,攻击者将其用户代理的会话标识符移植到受害者的用户代理。其次,受害者使用该会话标识符与服务器交互,可能将用户的凭证或机密信息赋予该会话标识符。第三,攻击者使用该会话标识符直接与服务器交互,可能获得用户的权限或机密信息。

8.5. 弱机密性

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

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

Cookies 不总是按路径提供隔离。尽管网络层协议不会将为一个路径存储的 cookie 发送到另一个路径,但一些用户代理通过非 HTTP API(如 HTML 的 document.cookie)暴露 cookies。由于某些用户代理(例如 Web 浏览器)并不隔离从不同路径接收的资源,一个从某路径检索的资源可能能够访问为另一路径存储的 cookies。

8.6. 弱完整性

Cookies 无法为兄弟域(及其子域)提供完整性保证。例如,考虑 foo.example.com 与 bar.example.com。foo.example.com 服务器可以设置 Domain 属性为 "example.com" 的 cookie(可能覆盖 bar.example.com 之前设置的 "example.com" cookie),并且用户代理会在对 bar.example.com 的 HTTP 请求中包含该 cookie。在最坏情况下,bar.example.com 将无法区分该 cookie 与它自己设置的 cookie。foo.example.com 服务器可能利用此能力对 bar.example.com 发动攻击。

尽管 Set-Cookie 首部支持 Path 属性,但 Path 属性并不提供任何完整性保护,因为用户代理会接受 Set-Cookie 首部中任意的 Path 属性。例如,对 http://example.com/foo/bar 的响应可以设置 Path 属性为 "/qux" 的 cookie。因此,服务器 不应 在同一主机的不同路径上运行相互不信任的服务并使用 cookies 存储安全敏感信息。

活动的网络攻击者也可以通过伪造来自 http://example.com/ 的响应并注入 Set-Cookie 首部,从而向发送到 https://example.com/ 的 Cookie 首部注入 cookies。example.com 的 HTTPS 服务器将无法将这些 cookie 与其自己在 HTTPS 响应中设置的 cookie 区分开。活动的网络攻击者可能利用此能力即使在 example.com 完全使用 HTTPS 的情况下也对其发起攻击。

服务器可以通过对 cookie 内容进行加密和签名来部分缓解这些攻击。然而,使用加密并不能完全缓解问题,因为攻击者可以在用户的会话中重放他或她从真实 example.com 服务器处获得的 cookie,导致不可预测的结果。

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

8.7. 对 DNS 的依赖

Cookies 对域名系统(DNS)的安全性有依赖。如果 DNS 部分或全部被攻破,cookie 协议可能无法为应用提供所需的安全属性。

9. IANA 注意事项

永久消息首部字段注册表(参见 [RFC3864])已根据下列注册信息进行了更新。

9.3. Cookie2

首部字段名:Cookie2

适用协议:http

状态:已废弃

作者/变更控制者:IETF

规范文档:[RFC2965]

9.4. Set-Cookie2

首部字段名:Set-Cookie2

适用协议:http

状态:已废弃

作者/变更控制者:IETF

规范文档:[RFC2965]

10. 参考文献

10.1. 规范性引用

[RFC1034]
Mockapetris, P., “Domain names - concepts and facilities”, STD 13, RFC 1034, November 1987.
[RFC1123]
Braden, R., “Requirements for Internet Hosts - Application and Support”, STD 3, RFC 1123, October 1989.
[RFC2119]
Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels”, BCP 14, RFC 2119, March 1997.
[RFC2616]
Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, “Hypertext Transfer Protocol -- HTTP/1.1”, RFC 2616, June 1999.
[RFC3490]
Faltstrom, P., Hoffman, P., and A. Costello, “Internationalizing Domain Names in Applications (IDNA)”, RFC 3490, March 2003.
See 第 6.3 节 for an explanation why the normative reference to an obsoleted specification is needed.
[RFC4790]
Newman, C., Duerst, M., and A. Gulbrandsen, “Internet Application Protocol Collation Registry”, RFC 4790, March 2007.
[RFC5234]
Crocker, D., Ed. and P. Overell, “Augmented BNF for Syntax Specifications: ABNF”, STD 68, RFC 5234, January 2008.
[RFC5890]
Klensin, J., “Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework”, RFC 5890, August 2010.
[USASCII]
American National Standards Institute, “Coded Character Set -- 7-bit American Standard Code for Information Interchange”, ANSI X3.4, 1986.

10.2. 补充性引用

[RFC2109]
Kristol, D. and L. Montulli, “HTTP State Management Mechanism”, RFC 2109, February 1997.
[RFC2965]
Kristol, D. and L. Montulli, “HTTP State Management Mechanism”, RFC 2965, October 2000.
[RFC2818]
Rescorla, E., “HTTP Over TLS”, RFC 2818, May 2000.
[Netscape]
Netscape Communications Corp., “Persistent Client State -- HTTP Cookies”, 1999, <http://web.archive.org/web/20020803110822/http://wp.netscape.com/newsref/std/cookie_spec.html>.
[Kri2001]
Kristol, D., “HTTP Cookies: Standards, Privacy, and Politics”, ACM Transactions on Internet Technology Vol. 1, #2, November 2001, <http://arxiv.org/abs/cs.SE/0105018>.
[RFC3629]
Yergeau, F., “UTF-8, a transformation format of ISO 10646”, STD 63, RFC 3629, November 2003.
[RFC4648]
Josefsson, S., “The Base16, Base32, and Base64 Data Encodings”, RFC 4648, October 2006.
[RFC3864]
Klyne, G., Nottingham, M., and J. Mogul, “Registration Procedures for Message Header Fields”, BCP 90, RFC 3864, September 2004.
[RFC5895]
Resnick, P. and P. Hoffman, “Mapping Characters for Internationalized Domain Names in Applications (IDNA) 2008”, RFC 5895, September 2010.
[UTS46]
Davis, M. and M. Suignard, “Unicode IDNA Compatibility Processing”, Unicode Technical Standards # 46, 2010, <http://unicode.org/reports/tr46/>.
[CSRF]
Barth, A., Jackson, C., and J. Mitchell, “Robust Defenses for Cross-Site Request Forgery”, 2008, <http://portal.acm.org/citation.cfm?id=1455770.1455782>.
[Aggarwal2010]
Aggarwal, G., Burzstein, E., Jackson, C., and D. Boneh, “An Analysis of Private Browsing Modes in Modern Browsers”, 2010, <http://www.usenix.org/events/sec10/tech/full_papers/Aggarwal.pdf>.

Appendix A. 致谢

本文大量借鉴了 RFC 2109 [RFC2109]。我们感谢 David M. Kristol 与 Lou Montulli 为规范 cookie 所付出的努力。尤其感谢 David M. Kristol 在引导 IETF 过程方面提供的宝贵建议。我们还要感谢 Thomas Broyer、Tyler Close、Alissa Cooper、Bil Corry、corvid、Lisa Dusseault、Roy T. Fielding、Blake Frantz、Anne van Kesteren、Eran Hammer-Lahav、Jeff Hodges、Bjoern Hoehrmann、Achim Hoffmann、Georg Koppen、Dean McNamee、Alexey Melnikov、Mark Miller、Mark Pauley、Yngve N. Pettersen、Julian Reschke、Peter Saint-Andre、Mark Seaborn、Maciej Stachowiak、Daniel Stenberg、Tatsuhiro Tsujikawa、David Wagner、Dan Winship 和 Dan Witte 对本文档提供的宝贵反馈。

作者地址

Adam Barth
University of California, Berkeley
Email: abarth@eecs.berkeley.edu
URI: http://www.adambarth.com/