使用 HTTP Cookie
Cookie(也称为网络 Cookie 或浏览器 Cookie)是服务器发送给用户网络浏览器的一小段数据。浏览器可以存储 Cookie、创建新 Cookie、修改现有 Cookie,并在后续请求中将其发送回同一服务器。Cookie 使网络应用程序能够存储有限数量的数据并记住状态信息;默认情况下,HTTP 协议是无状态的。
在本文中,我们将探讨 Cookie 的主要用途,解释使用它们的最佳实践,并审视它们对隐私和安全的影响。
Cookie 的用途
通常,服务器会使用 HTTP Cookie 的内容来确定不同请求是否来自同一个浏览器/用户,然后酌情发出个性化或通用响应。以下描述了一个基本的用户登录系统:
- 用户向服务器发送登录凭据,例如通过表单提交。
- 如果凭据正确,服务器会更新 UI 以指示用户已登录,并返回一个包含会话 ID 的 Cookie,该 Cookie 会记录用户在浏览器上的登录状态。
- 稍后,用户导航到同一网站上的另一个页面。浏览器会随相应的请求一起发送包含会话 ID 的 Cookie,以表明它仍然认为用户已登录。
- 服务器检查会话 ID,如果仍然有效,则向用户发送新页面的个性化版本。如果无效,则删除会话 ID,并向用户显示该页面的通用版本(或者显示“拒绝访问”消息并要求重新登录)。

Cookie 主要用于三个目的:
- 会话管理:用户登录状态、购物车内容、游戏分数或服务器需要记住的任何其他与用户会话相关的详细信息。
- 个性化:用户偏好,例如显示语言和 UI 主题。
- 跟踪:记录和分析用户行为。
数据存储
在网络早期没有其他选择时,Cookie 被用于一般客户端数据存储目的。现在推荐使用现代存储 API,例如Web Storage API (localStorage 和 sessionStorage) 和IndexedDB。
它们在设计时就考虑到了存储,从不向服务器发送数据,并且没有使用 Cookie 进行存储的其他缺点:
- 浏览器通常限制每个域的最大 Cookie 数量(因浏览器而异,通常为数百个)和每个 Cookie 的最大大小(通常为 4KB)。存储 API 可以存储更多数据。
- Cookie 会随每个请求发送,因此它们可能会降低性能(例如在缓慢的移动数据连接上),尤其是当您设置了大量 Cookie 时。
创建、移除和更新 Cookie
收到 HTTP 请求后,服务器可以通过响应发送一个或多个Set-Cookie 标头,每个标头都会设置一个单独的 Cookie。Cookie 通过指定一个名称-值对来设置,如下所示:
Set-Cookie: <cookie-name>=<cookie-value>
以下 HTTP 响应指示接收浏览器存储一对 Cookie:
HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: yummy_cookie=chocolate
Set-Cookie: tasty_cookie=strawberry
[page content]
注意:了解如何在各种服务器端语言/框架中使用 Set-Cookie 标头:PHP、Node.js、Python、Ruby on Rails。
发出新请求时,浏览器通常会在Cookie HTTP 标头中将先前存储的当前域的 Cookie 发送回服务器:
GET /sample_page.html HTTP/2.0
Host: www.example.org
Cookie: yummy_cookie=chocolate; tasty_cookie=strawberry
删除:定义 Cookie 的生命周期
您可以指定一个过期日期或时间段,在此之后 Cookie 应被删除且不再发送。根据创建 Cookie 时Set-Cookie 标头中设置的属性,它们可以是永久或会话Cookie:
-
永久 Cookie 在
Expires属性中指定的日期之后删除httpSet-Cookie: id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT;或在
Max-Age属性中指定的期限之后删除httpSet-Cookie: id=a3fWa; Max-Age=2592000注意:
Expires的可用时间比Max-Age长,但是Max-Age更不容易出错,并且在两者都设置时具有优先权。其原理是,当您设置Expires日期和时间时,它们是相对于设置 Cookie 的客户端而言的。如果服务器设置为不同的时间,这可能会导致错误。 -
会话 Cookie——没有
Max-Age或Expires属性的 Cookie——在当前会话结束时删除。浏览器定义“当前会话”何时结束,有些浏览器在重新启动时使用会话恢复。这可能导致会话 Cookie 无限期地持续存在。注意:如果您的网站对用户进行身份验证,它应该在用户进行身份验证时重新生成并重新发送会话 Cookie,即使是已经存在的 Cookie。这种方法有助于防止会话固定攻击,其中第三方可以重用用户的会话。
要立即删除 Cookie,请使用相同的名称、路径和域(如果已指定)再次设置 Cookie,并将其 Expires 属性设置为过去的日期或将其 Max-Age 属性设置为 0 或负值。这会指示浏览器立即删除 Cookie。例如:
Set-Cookie: id=a3fWa; Max-Age=0
您还可以使用Clear-Site-Data 响应头清除与可注册域关联的所有 Cookie。例如,从 https://foo.example.com/ 发送的以下头将清除由 example.com 及其所有子域(例如 all.bar.example.com)发送的所有 Cookie。
Clear-Site-Data: "cookies"
有一些技术旨在在 Cookie 被删除后重新创建它们。这些被称为“僵尸”Cookie。这些技术违反了用户隐私和控制的原则,可能违反数据隐私法规,并可能使使用它们的网站面临法律责任。
更新 Cookie 值
要通过 HTTP 更新 Cookie,服务器可以发送一个Set-Cookie 标头,其中包含现有 Cookie 的名称和新值。例如:
Set-Cookie: id=new-value
您可能希望这样做有几个原因,例如用户更新了他们的偏好设置,并且应用程序希望在客户端数据中反映这些更改(您也可以使用客户端存储机制,例如Web Storage)。
通过 JavaScript 更新 Cookie
在浏览器中,您可以使用Document.cookie 属性或异步Cookie Store API 通过 JavaScript 创建新的 Cookie。请注意,以下所有示例都使用 Document.cookie,因为它是支持最广泛/最成熟的选项。
document.cookie = "yummy_cookie=chocolate";
document.cookie = "tasty_cookie=strawberry";
您还可以访问现有 Cookie 并为其设置新值:
console.log(document.cookie);
// logs "yummy_cookie=chocolate; tasty_cookie=strawberry"
document.cookie = "yummy_cookie=blueberry";
console.log(document.cookie);
// logs "tasty_cookie=strawberry; yummy_cookie=blueberry"
出于安全目的,您无法通过在发起请求时直接发送更新的 Cookie 标头来更改 Cookie 值,例如通过fetch() 或XMLHttpRequest。
有一些充分的理由不应该允许 JavaScript 根本修改 Cookie。您可以通过在其创建期间指定HttpOnly 属性来阻止 JavaScript 访问 Cookie。有关更多详细信息,请参阅安全部分。
安全
当您在 Cookie 中存储信息时,默认情况下,所有 Cookie 值对最终用户都是可见的,并且可以由最终用户更改。您真的不希望您的 Cookie 被滥用——例如被不良行为者访问/修改,或发送到不应该发送到的域。潜在的后果可能从令人烦恼的(应用程序无法正常工作或表现出奇怪的行为)到灾难性的。例如,犯罪分子可以窃取会话 ID 并使用它来设置一个 Cookie,使其看起来像是他们以其他人的身份登录,从而控制他们的银行或电子商务账户。
您可以通过多种方式保护您的 Cookie,本节将对此进行回顾。
阻止访问您的 Cookie
您可以通过两种方式确保 Cookie 安全发送且不会被意外方或脚本访问:使用 Secure 属性和 HttpOnly 属性:
Set-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly
-
带有
Secure属性的 Cookie 仅通过 HTTPS 协议随加密请求发送到服务器。它绝不会随不安全的 HTTP 发送(除了在 localhost 上),这意味着中间人攻击者无法轻易访问它。不安全的站点(URL 中带有http:)无法设置带有Secure属性的 Cookie。但是,不要假设Secure可以阻止对 Cookie 中敏感信息的所有访问。例如,有权访问客户端硬盘(或 JavaScript,如果未设置HttpOnly属性)的人可以读取和修改信息。 -
带有
HttpOnly属性的 Cookie 无法被 JavaScript 访问,例如使用Document.cookie;它只能在到达服务器时才能访问。例如,持久化用户会话的 Cookie 应该设置HttpOnly属性——将它们提供给 JavaScript 会非常不安全。这种预防措施有助于缓解跨站脚本(XSS)攻击。
注意:根据应用程序的不同,您可能希望使用服务器查找的不透明标识符,而不是直接将敏感信息存储在 Cookie 中,或者研究替代的身份验证/保密机制,例如JSON Web Tokens。
定义 Cookie 的发送位置
Domain 和 Path 属性定义了 Cookie 的范围:Cookie 发送到哪些 URL。
-
Domain属性指定哪个服务器可以接收 Cookie。如果指定,Cookie 在指定的服务器及其子域上可用。例如,如果您从mozilla.org设置Domain=mozilla.org,则 Cookie 在该域和developer.mozilla.org等子域上可用。httpSet-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly; Domain=mozilla.org如果
Set-Cookie标头未指定Domain属性,则 Cookie 在设置它的服务器上可用,但不在其子域上可用。因此,指定Domain比省略它限制更少。请注意,服务器只能将其Domain属性设置为其自己的域或父域,而不能设置为子域或其他域。因此,例如,域为foo.example.com的服务器可以将属性设置为example.com或foo.example.com,但不能设置为bar.foo.example.com或elsewhere.com(Cookie 仍然会发送到子域,例如bar.foo.example.com)。有关更多详细信息,请参阅无效域。 -
Path属性指示请求 URL 中必须存在的 URL 路径,才能发送Cookie标头。例如:httpSet-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly; Path=/docs%x2F("/") 字符被视为目录分隔符,子目录也匹配。例如,如果您设置Path=/docs,这些请求路径将匹配:/docs/docs//docs/Web//docs/Web/HTTP
但这些请求路径不匹配:
//docsets/en-US/docs
注意:
path属性允许您根据网站的不同部分控制浏览器发送哪些 Cookie。它不作为安全措施,并且不保护免受从不同路径对 Cookie 的未经授权的读取。
使用 SameSite 控制第三方 Cookie
SameSite 属性允许服务器指定是否/何时随跨站点请求发送 Cookie——即第三方 Cookie。跨站点请求是指站点(可注册域)和/或方案(http 或 https)与用户当前访问的站点不匹配的请求。这包括当点击其他网站上的链接导航到您的网站时发送的请求,以及嵌入式第三方内容发送的任何请求。
SameSite 有助于防止信息泄露,保护用户隐私,并提供针对跨站点请求伪造攻击的一些保护。它有三个可能的值:Strict、Lax 和 None:
-
Strict导致浏览器仅在响应来自 Cookie 源站点的请求时发送 Cookie。当您的 Cookie 与始终位于初始导航之后的功能(例如身份验证或存储购物车信息)相关时,应该使用此选项。httpSet-Cookie: cart=110045_77895_53420; SameSite=Strict注意:用于敏感信息的 Cookie 也应该具有较短的生命周期。
-
Lax类似,只是浏览器在用户导航到 Cookie 的源站点时也会发送 Cookie(即使用户来自不同的站点)。这对于影响站点显示的 Cookie 很有用——例如,您可能在您的网站上有一个包含联盟链接的合作伙伴产品信息。当该链接被跟踪到合作伙伴网站时,他们可能希望设置一个 Cookie,说明已跟踪了联盟链接,这将显示奖励横幅并在购买产品时提供折扣。httpSet-Cookie: affiliate=e4rt45dw; SameSite=Lax -
None指定在源请求和跨站点请求中都发送 Cookie。如果您希望随嵌入在其他站点中的第三方内容(例如广告技术或分析提供商)发出的请求发送 Cookie,这很有用。请注意,如果设置了SameSite=None,则还必须设置Secure属性——SameSite=None需要安全上下文。httpSet-Cookie: widget_session=7yjgj57e4n3d; SameSite=None; Secure; HttpOnly
如果没有设置 SameSite 属性,则默认将 Cookie 视为 Lax。
Cookie 前缀
由于 Cookie 机制的设计,服务器无法确认 Cookie 是否从安全来源设置,甚至无法判断 Cookie 最初在何处设置。
子域上的应用程序可以设置具有 Domain 属性的 Cookie,这使得可以在所有其他子域上访问该 Cookie。这种机制可能在会话固定攻击中被滥用。
作为纵深防御措施,您可以使用Cookie 前缀对支持的用户代理中的 Cookie 属性施加特定限制。所有 Cookie 前缀都以双下划线(__)开头并以破折号(-)结尾。有四个前缀可用:
__Secure-:名称以__Secure-开头的 cookie 必须由安全页面 (HTTPS) 设置Secure属性。__Host-:名称以__Host-开头的 cookie 必须由安全页面 (HTTPS) 设置Secure属性。此外,它们不能指定Domain属性,并且Path属性必须设置为/。这保证了此类 cookie 仅发送给设置它们的主机,而不发送给域上的任何其他主机。它还保证它们在主机范围内设置,并且不能被该主机上的任何路径覆盖。这种组合产生了一个尽可能接近将来源视为安全边界的 cookie。__Http-:名称以__Http-开头的 Cookie 必须由安全页面 (HTTPS) 设置Secure标志,并且还必须设置HttpOnly属性以证明它们是通过Set-Cookie标头设置的(它们不能通过 JavaScript 功能(例如Document.cookie或Cookie Store API)设置或修改)。__Host-Http-:名称以__Host-Http-开头的 cookie 必须由安全页面 (HTTPS) 设置Secure标志,并且必须设置HttpOnly属性以证明它们是通过Set-Cookie头设置的。此外,它们还具有与__Host-前缀 cookie 相同的限制。这种组合产生了一个尽可能接近将来源视为安全边界的 cookie,同时确保开发人员和服务器操作员知道其范围仅限于 HTTP 请求。
浏览器将拒绝不符合其限制的带有这些前缀的 Cookie。由于应用程序服务器在确定用户是否已通过身份验证或 CSRF 令牌是否正确时仅检查特定的 Cookie 名称,因此这实际上是针对会话固定的防御措施。
注意:在服务器上,Web 应用程序必须检查包括前缀在内的完整 Cookie 名称。用户代理在请求的Cookie 标头中发送 Cookie 之前不会去除前缀。
有关 Cookie 前缀和浏览器支持当前状态的更多信息,请参阅Set-Cookie 参考文章的前缀部分。
隐私与追踪
早些时候我们讨论了 SameSite 属性如何用于控制何时发送第三方 Cookie,以及这如何有助于保护用户隐私。隐私是构建网站时非常重要的考虑因素,如果做得好,可以与您的用户建立信任。如果做得不好,它可能会完全侵蚀这种信任并导致各种其他问题。
第三方 Cookie 可以由通过<iframe> 嵌入在网站中的第三方内容设置。它们有许多合法用途,包括共享用户配置文件信息、计算广告展示次数或跨不同相关域收集分析数据。
然而,第三方 Cookie 也可能被用来创建令人毛骨悚然、侵入性的用户体验。第三方服务器可以根据同一浏览器在访问多个网站时发送给它的 Cookie 来创建用户浏览历史和习惯的配置文件。典型的例子是,当您在一个网站上搜索产品信息时,无论您走到哪里,都会被类似产品的广告追逐。
浏览器供应商知道用户不喜欢这种行为,因此都已开始默认阻止第三方 Cookie,或者至少计划朝这个方向发展。第三方 Cookie(或仅跟踪 Cookie)也可能被其他浏览器设置或扩展程序阻止。
注意:Cookie 阻止可能导致某些第三方组件(例如社交媒体小部件)无法按预期运行。随着浏览器对第三方 Cookie 施加更多限制,开发人员应该开始寻找减少对它们依赖的方法。
有关第三方 Cookie、与之相关的问题以及可用替代方案的详细信息,请参阅我们的第三方 Cookie 文章。有关隐私的更多信息,请参阅我们的隐私着陆页。
与 Cookie 相关的法规
涵盖 Cookie 使用的法律法规包括:
- 欧盟的通用数据隐私条例 (GDPR)
- 欧盟的 ePrivacy 指令
- 加州消费者隐私法案
这些法规具有全球影响力。它们适用于来自这些司法管辖区(欧盟和加利福尼亚州,但加利福尼亚州的法律仅适用于总收入超过 2500 万美元的实体等)的用户访问的任何万维网站。
这些法规包括以下要求:
- 通知用户您的网站使用 Cookie。
- 允许用户选择退出接收部分或全部 Cookie。
- 允许用户在不接收 Cookie 的情况下使用您的大部分服务。
您所在地区可能还有其他管理 Cookie 使用的法规。您有责任了解并遵守这些法规。有些公司提供“Cookie 横幅”代码,可帮助您遵守这些法规。
注意:公司应披露其网站上使用的 Cookie 类型,以实现透明度并遵守法规。例如,请参阅Google 关于其使用的 Cookie 类型的通知,以及 Mozilla 的网站、通信和 Cookie 隐私通知。
另见
- 相关 HTTP 标头:
Set-Cookie、Cookie - 相关 JavaScript API:
Document.cookie、Navigator.cookieEnabled、Cookie Store API - 第三方 cookie
- Cookie 规范:RFC 6265
- Cookie、GDPR 和 ePrivacy 指令