Cookie 详细介绍

0 阅读15分钟

本文整理自 MDN: HTTP CookieRFC 6265: HTTP State Management Mechanism

一、什么是 Cookie

HTTP Cookie(也称 Web Cookie、浏览器 Cookie)是服务器通过 HTTP 响应发送到用户浏览器并保存在本地的一小块数据。浏览器会存储这些 Cookie,并在下次向同一服务器再发起请求时,通过请求头自动携带发送。通常用于告知服务端:两个请求是否来自同一浏览器,从而在无状态的 HTTP 协议上维持稳定状态(如保持用户登录)[MDN]。

  • 发明与历史:Lou Montulli(Netscape,1994);RFC 2109、RFC 2965 已被 RFC 6265(2011)取代,Cookie2/Set-Cookie2 已废弃 [RFC 6265]。
  • 标准:RFC 6265 定义 CookieSet-Cookie 两个头部,并指出 Cookie 存在诸多历史遗留的安全与隐私问题,但仍被广泛使用。

二、Cookie 的三大用途 [MDN]

用途说明
会话状态管理用户登录状态、购物车、游戏分数等需记录的信息
个性化设置用户自定义设置、主题等
浏览器行为跟踪跟踪与分析用户行为(常涉及隐私与合规)

注意:Cookie 曾作为客户端唯一存储手段被滥用;现在若不需要在每次请求中携带数据,推荐使用现代存储 API(如 Web Storage、IndexedDB),以减少请求头体积与性能开销,尤其在移动端 [MDN]。 在浏览器中查看 Cookie:开发者工具 → 存储/StorageStorage Inspector → 选中 Cookie [MDN]。


三、创建与传递:Set-Cookie 与 Cookie 头

3.1 基本流程

  1. 服务器在 HTTP 响应头里添加一个或多个 Set-Cookie
  2. 浏览器保存这些 Cookie,之后向同一服务器发请求时,在 Cookie 请求头里一并发送 [MDN]。

示例 [MDN]:

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

[页面内容]

后续请求:

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

注意:不应将多个 Set-Cookie 折叠成一行(HTTP 头部折叠可能改变语义,因为逗号在 Set-Cookie 中有特殊含义)[RFC 6265]。 服务端如何设置 Set-Cookie 可参考 MDN 示例:PHP、Node.js、Python、Ruby on Rails 等 [MDN]。

3.2 语法概要(RFC 6265)

  • Set-Cookie 格式:Set-Cookie: <cookie-name>=<cookie-value>,后可跟若干属性(; Expires=...; Max-Age=...; Domain=...; Path=...; Secure; HttpOnly 等)。
  • Cookie 请求头:Cookie: cookie-pair *( "; " cookie-pair ),仅包含名值对,不包含过期时间、域、路径、Secure、HttpOnly 等属性,服务端无法从 Cookie 头 alone 得知这些元数据 [RFC 6265]。

四、Cookie 的生命周期

4.1 会话期 vs 持久性 [MDN][RFC 6265]

  • 会话期 Cookie(Session Cookie)

    • 不设置 Expires 且不设置 Max-Age(或 Max-Age=0)。
    • 当前会话结束后被删除。注意:“当前会话”由浏览器定义,部分浏览器在重启时会做会话恢复,可能导致会话 Cookie 被保留更久 [MDN]。
    • RFC 6265:此类 Cookie 的 persistent-flag 为 false,expiry-time 为“会话结束”。
  • 持久性 Cookie(Persistent Cookie)

    • 通过 Expires(日期/时间)或 Max-Age(秒数)指定存活期。
    • 在过期前会一直存在(除非用户或浏览器策略清除)。
    • Max-Age 优先于 Expires;若两者都存在,以 Max-Age 为准。若 Max-Age 为 0 或负数,表示立即过期 [RFC 6265]。

示例 [MDN]:

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

重要Expires 的日期时间是客户端解释的,与服务器时区无关 [MDN]。 若站点对用户做身份验证,建议在每次验证时重新生成并重新发送会话 Cookie(包括已存在的),以减轻会话固定攻击(Session Fixation)[MDN]。

4.2 删除 Cookie

服务端可通过发送同名、同 Domain、同 Path 的 Cookie,并将 Expires 设为过去的时间(或 Max-Age=0)来删除 Cookie [RFC 6265][MDN]。


五、限制 Cookie 的访问与发送

5.1 Secure

  • Secure 的 Cookie 仅应通过安全通道(通常为 HTTPS/TLS)发送,不会在不安全的 HTTP 请求中发送(本地主机除外)[MDN]。
  • 不安全的站点(URL 为 http:)无法设置带 Secure 的 Cookie [MDN]。
  • 注意:Secure 只保护机密性(传输中不被窃听),不提供完整性。主动网络攻击者仍可能通过不安全通道注入或覆盖 Cookie,破坏其完整性 [RFC 6265]。

5.2 HttpOnly

  • HttpOnly 的 Cookie 不能被 JavaScript 的 document.cookie 等“非 HTTP API”访问,仅用于 HTTP 请求 [MDN][RFC 6265]。
  • 服务端会话 Cookie 通常不需要对 JS 可见,应设置 HttpOnly,以缓解 XSS 窃取会话 [MDN]。

示例 [MDN]:

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

六、定义 Cookie 的发送范围:Domain、Path、SameSite

6.1 Domain [MDN][RFC 6265]

  • 不指定 Domain:默认为当前 host不包含子域(即仅当前域名)。
  • 指定 Domain:如 Domain=mozilla.org,则子域(如 developer.mozilla.org)也会收到该 Cookie。指定 Domain 会扩大作用域。
  • 用户代理会拒绝 Domain 不包含当前 origin 的 Cookie;许多浏览器还会拒绝将 公共后缀(如 comco.uk)设为 Domain,以防止恶意站点为整片顶级域设置 Cookie [RFC 6265]。

6.2 Path [MDN][RFC 6265]

  • Path 指定 URL 路径前缀;只有请求的 URL 路径与该 Path 匹配(或为其子路径)时才会发送 Cookie。
  • 路径以 %x2F("/")为分隔符;子路径会匹配。例如 Path=/docs 会匹配:
    • /docs/docs//docs/Web//docs/Web/HTTP
  • 不匹配://docsets/fr/docs [MDN]。
  • 若省略 Path,默认值为当前请求 URI 的路径的“目录”部分 [RFC 6265]。
  • 安全提醒:Path 不能作为安全边界依赖;同一主机上不同路径的互不信任服务不应仅靠 Path 隔离敏感 Cookie [RFC 6265]。

6.3 SameSite [MDN]

  • SameSite 控制是否在跨站请求中发送 Cookie(“站点”由注册域和协议 http/https 共同定义),用于减轻 CSRF
  • 取值:
    • Strict:仅在同站请求中发送。
    • Lax:与 Strict 类似,但在用户从外站导航到该站时(如点击链接)也会发送。
    • None:同站与跨站请求都会发送;必须同时设置 Secure(即仅在安全上下文中)[MDN]。
  • 未设置 SameSite 时,现代浏览器多将其视为 Lax(此前默认行为是更宽松的“始终发送”)[MDN]。
  • 同一注册域下,若协议不同(http vs https),视为不同站点 [MDN]。

示例:

Set-Cookie: mykey=myvalue; SameSite=Strict

七、Cookie 前缀(__Host- 与 __Secure-)[MDN]

由于 Cookie 机制无法让服务端确认 Cookie 是否在安全来源设置、甚至无法确认最初设置者,子域上的漏洞可能通过 Domain 为父域设置 Cookie,被用于会话劫持。作为深度防御,可使用 Cookie 前缀

  • __Host- 仅当同时满足以下条件时,浏览器才接受 Set-Cookie:

    • Secure
    • 安全来源发送;
    • 包含 Domain
    • Path/。 此类 Cookie 可视为“锁定到当前 host”。
  • __Secure- 仅当带 Secure 且从安全来源发送时才接受,限制弱于 __Host-

不符合前缀要求的 Cookie 会被浏览器拒绝。应用服务器必须校验完整 Cookie 名称;用户代理在发送 Cookie 头时不会去掉前缀 [MDN]。


八、浏览器存储模型与发送规则(RFC 6265 要点)

  • 用户代理为每个 Cookie 存储:name、value、expiry-time、domain、path、creation-time、last-access-time、persistent-flag、host-only-flag、secure-only-flag、http-only-flag。
  • 发送 Cookie 时:只发送与请求的 host(或 Domain 匹配)、Path 匹配、未过期、且满足 Secure(若为 secure-only)的 Cookie;若通过“非 HTTP API”生成请求(如 document.cookie),则包含 http-only-flag 为 true 的 Cookie。
  • Eviction(驱逐):过期 Cookie 会先被删除;若单域或全局 Cookie 数量超限,可按实现定义的策略删除(RFC 建议优先删过期,再删同域过多的,再删全局过多的;同优先级时删 last-access-time 最早的)。
  • 实现建议下限:每 Cookie 至少 4096 字节(名+值+属性总长)、每域至少 50 个 Cookie、全局至少 3000 个 Cookie;服务端应尽量少而小,并做好用户代理未返回某些 Cookie 时的降级 [RFC 6265]。

九、JavaScript 与 Document.cookie [MDN]

  • 通过 Document.cookie创建新 Cookie,也可读取现有 Cookie(仅限设置 HttpOnly 的)。
  • 由 JavaScript 创建的 Cookie 不能包含 HttpOnly [MDN]。

示例 [MDN]:

document.cookie = "yummy_cookie=choco";
document.cookie = "tasty_cookie=strawberry";
console.log(document.cookie);
// 输出 "yummy_cookie=choco; tasty_cookie=strawberry"

安全:Cookie 值可被用户或脚本访问与修改,需注意 XSS。敏感场景建议使用服务端查证的不透明标识符,或考虑 JWT 等替代方案;在不可信环境中不要通过 HTTP Cookie 存储或传输敏感信息 [MDN]。


十、安全考量 [MDN][RFC 6265]

10.1 缓解措施

  • 使用 HttpOnly 防止通过 JS 读取 Cookie。
  • 敏感 Cookie(如身份验证)应生存期短,并设置 SameSite=Strict 或 Lax,避免在跨站请求中发送 [MDN]。

10.2 常见风险

  • 环境权威(Ambient Authority)与 CSRF:Cookie 随请求自动携带,易被跨站请求伪造;应配合 SameSite、CSRF Token 等 [RFC 6265]。
  • 明文传输:非 HTTPS 时 Cookie 明文传输,易被窃听与篡改;敏感 Cookie 应配合 Secure 与 HTTPS [RFC 6265]。
  • 会话固定(Session Fixation):攻击者将已知会话 ID 植入受害者浏览器 → 受害者用该 ID 登录 → 攻击者用同一 ID 冒充。缓解:每次认证后重新签发会话 Cookie [MDN][RFC 6265]。
  • 弱机密性:Cookie 不按端口、不按协议(http/https)隔离,同一 host 不同端口/协议可能共享 Cookie;不可在同一主机上对互不信任的服务依赖 Cookie 做敏感隔离 [RFC 6265]。
  • 弱完整性:同父域下不同子域可互相覆盖 Domain 为父域的 Cookie;主动攻击者还可通过 HTTP 响应注入 Set-Cookie,影响 HTTPS 站点的 Cookie。加密/签名 Cookie 内容可部分缓解,但无法防止重放 [RFC 6265]。
  • 依赖 DNS:Cookie 安全依赖 DNS;DNS 被篡改时,Cookie 提供的安全属性可能失效 [RFC 6265]。

十一、跟踪与隐私 [MDN][RFC 6265]

11.1 第一方 vs 第三方 Cookie

  • 第一方 Cookie:Cookie 的域和协议与当前页面一致(或为当前页面的子域等符合 Domain 规则)。
  • 第三方 Cookie:由页面中引用的其他域(如广告、统计)设置;同一第三方在不同站点可收到同一 Cookie,从而跨站跟踪用户 [MDN][RFC 6265]。
  • 许多浏览器已限制或计划淘汰第三方 Cookie(如 Firefox 默认阻止已知跟踪器);服务器可通过 SameSite 控制是否在跨站场景下发送 [MDN]。

11.2 法规与合规 [MDN]

涉及 Cookie 的法规包括(具有全球影响):

  • 欧盟 GDPR(通用数据保护条例)
  • 欧盟 ePrivacy 指令
  • 加州 CCPA(加州消费者隐私法;通常适用于年收入超过一定规模的实体)

常见要求:向用户告知使用 Cookie、允许用户拒绝部分或全部 Cookie、在用户拒绝 Cookie 时仍能使用主要服务。部分公司提供“Cookie 横幅”等方案以辅助合规 [MDN]。

11.3 各浏览器对第三方 Cookie 的政策(按浏览器与版本)

不同浏览器、不同版本对第三方 Cookie 的限制差异很大;以下按浏览器与版本范围整理,便于兼容性判断与迁移规划。策略会随版本更新变化,以各厂商官方文档为准。

Safari(WebKit)

时间 / 版本策略概要
2017 年 6 月(ITP 1.0)引入 Intelligent Tracking Prevention (ITP):用机器学习识别跨站跟踪域并限制其 Cookie;未访问站点 30 天后清除其 Cookie;第三方上下文中对 Cookie 做分区。
2019 年 2 月(ITP 2.1)强化对已知跟踪域的限制与分类。
2019 年 4 月(ITP 2.2)防止通过链接装饰(URL 参数/片段)跨站跟踪:被分类域通过带 query/fragment 的链接导航时,通过 document.cookie 创建的持久 Cookie 寿命被限制为约 1 天
2019 年 9 月(ITP 2.3)所有脚本可写的网站数据(含 Cookie、Storage)在从被分类域导航后,寿命上限为 7 天document.referrer 降级为 eTLD+1,减少通过 referrer 泄露点击 ID。
2020 年 3 月Safari 13.1 / iOS 13.4 / iPadOS 13.4默认全面阻止所有第三方 Cookie(无例外),成为主流浏览器中首个默认全阻的;同时限制脚本可写存储的 7 天寿命、禁用登录指纹等。跨站嵌入若需 Cookie,需通过 Storage Access API 向用户请求授权。

小结:Safari 13.1+(macOS/iOS/iPadOS 对应版本起)默认即“全阻”第三方 Cookie;更早版本通过 ITP 逐步收紧,仍以“限制跟踪域 + 分区/短期”为主,而非一刀切全阻。

Firefox

时间 / 版本策略概要
2019 年 6 月Enhanced Tracking Protection (ETP) 对新安装默认开启;2019 年 9 月推广到所有用户。默认阻止已知跟踪器、指纹等,对第三方 Cookie 按“跟踪列表”限制。
2021 年 2 月引入 Total Cookie Protection (TCP):为每个网站维护独立“Cookie 罐”,第三方 Cookie 不能跨站共享,实质阻止跨站跟踪。初期主要在严格模式或可选开启。
2022 年 6 月TCP 开始向更多用户默认推广。
2024–2025 年Total Cookie Protection 在标准模式(Standard)下默认开启,逐步覆盖所有平台(Windows、macOS、Linux、Android),第三方 Cookie 按站点隔离,无法用于跨站跟踪。

小结:Firefox 当前(ETP 默认 + TCP 默认)下,第三方 Cookie 被“按站隔离”,等同阻止跨站跟踪;用户仍可在设置中按站点允许 Cookie。

Chrome(Chromium)

时间 / 版本策略概要
2020 年 2 月(Chrome 80)SameSite 默认行为变更:未指定 SameSite 的 Cookie 视为 SameSite=Lax,跨站子请求(如 iframe、img)不再携带这些 Cookie;需跨站携带必须显式 SameSite=None; Secure。同年 4 月曾因疫情短暂回滚,7 月恢复。
2020–2024 年不默认阻止第三方 Cookie;仅无痕模式或用户手动在 chrome://settings 中开启“阻止第三方 Cookie”时才会阻。原计划 2022/2023 淘汰第三方 Cookie 并推 Privacy Sandbox(如 FLoC),多次推迟。
2024–2025 年在部分渠道(约 1% 稳定版、约 20% Canary/Dev/Beta)试验性限制第三方 Cookie;计划从 2025 年起继续推进第三方 Cookie 弃用,与 Privacy Sandbox(CHIPS 分区 Cookie、Storage Access API、Related Website Sets、FedCM 等)配合,具体时间表以 Google 开发者公告为准。

小结:Chrome 目前仍以 SameSite 默认 Lax 为主,未全局默认“阻第三方”;淘汰时间表与 Privacy Sandbox 绑定,会随政策与反馈调整。

Microsoft Edge(Chromium)

时间 / 版本策略概要
2019 年 12 月(Edge 79)引入 Tracking Prevention:三档——Basic(仅恶意跟踪/挖矿等)、Balanced(默认)、Strict。Balanced 基于“站点参与度”阻止未互动站点的跟踪器,并扩大阻止类别(如 Content 类)。
2020 年 1 月(Edge 80)跟踪防护默认开启,与 Chrome 的 SameSite 变更同期。
Edge 77+企业策略 BlockThirdPartyCookies 可强制在普通浏览中阻止第三方 Cookie(InPrivate 不受该策略约束)。

小结:Edge 默认不“全阻”第三方 Cookie,而是按跟踪列表 + 参与度启发式限制;Strict 模式最严,Balanced 在隐私与兼容之间折中。

其他浏览器(简要)

  • Brave:自 2019 年 11 月 1.0 起默认阻止广告与跟踪器,第三方跟踪 Cookie 默认被阻。
  • Opera:约 2019 年 10 月起内置反跟踪,策略类似“阻止已知跟踪列表”,非全阻第三方 Cookie。

汇总表(当前默认行为,约 2024–2025)

浏览器默认是否阻止/限制第三方 Cookie说明
Safari(13.1+)✅ 默认全部阻止跨站嵌入需 Storage Access API 申请权限。
Firefox(ETP+TCP 默认)✅ 按站隔离,等同阻止跨站跟踪每站独立 Cookie 罐,第三方无法跨站共享。
Chrome❌ 不默认阻止SameSite 默认 Lax;淘汰计划进行中,部分用户已进入试验限制。
Edge⚠️ 默认限制跟踪器,非全阻Balanced 默认;Strict 最严。
Brave✅ 默认阻止跟踪 Cookie与广告拦截一体。

开发建议:若依赖跨站 Cookie(如嵌入式登录、跨站分析),应显式设置 SameSite=None; Secure,并尽早评估 Storage Access APICHIPS(Partitioned Cookie)Related Website Sets 等替代方案,以兼容 Safari 与未来 Chrome 的变更。


十二、其他浏览器存储方式 [MDN]

机制说明
Web StoragesessionStorage(会话、关标签即清)与 localStorage(长期);容量大于 Cookie,且不会随每次请求发送到服务器。
IndexedDB存储更大量、结构化数据。

“僵尸”Cookie(Zombie Cookie):在 Cookie 被删后通过其他存储或脚本重新创建 Cookie。此类做法损害用户隐私与控制权,可能违反数据隐私法规并带来法律风险,不应使用 [MDN]。


十三、小结

  • Cookie 由服务端通过 Set-Cookie 下发,浏览器在后续符合域、路径、安全、SameSite 等条件的请求中通过 Cookie 头自动携带,用于在无状态 HTTP 上维持状态 [MDN][RFC 6265]。
  • 通过 Expires/Max-Age、Domain、Path、Secure、HttpOnly、SameSite 及前缀 __Host- / __Secure- 可控制生命周期、作用域与安全性。
  • 在浏览器中,发送逻辑由用户代理按 RFC 与扩展(如 SameSite)实现;JS 仅能读写非 HttpOnly 的 Cookie。
  • 建议:敏感 Cookie 使用 HttpOnly + Secure + SameSite,配合 CSRF 防护与短生存期;避免用 Cookie 存敏感明文;关注第三方 Cookie 限制与隐私法规。

参考