你想知道的 HTTP Cookie 都在这

学前端

共 6944字,需浏览 14分钟

 · 2024-04-10

1 为什么有 Cookie

1.1 背景

客户端和服务器通过 HTTP 协议通信,它是一种无状态的协议,客户端每次发送请求时,首先要和服务器端建立一个连接,在请求完成后又会断开这个连接。这种方式可以节省传输时占用的连接资源,但同时也存在一个问题:每次请求都是独立的,服务器端无法判断本次请求和上一次请求是否来自同一个用户。

为了解决 HTTP 无状态的问题,Lou Montulli 在 1994 年的时候,推出了 Cookie。

1.2 什么是 Cookie

HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,浏览器会存储 Cookie 并在下次发起请求时携带。如下图示例:

89d82d0dc82ac05e99a951d0f99416a5.webp

注:根据 HTTP 协议的规定,每个域名下的 Cookie 总大小不能超过4KB(4096字节)。如果超过该限制,浏览器会自动截断 Cookie 内容。

2 如何种 Cookie

2.1 后端

e9c00d82812ac2a89acd1ce9e5dd4ad2.webp


服务端示例代码(node)

      
      const https = require('https');
const path = require('path');
const fs = require('fs');

let cookieNum = 0;

const server = https.createServer(options, (req, res) => {
  if (req.headers.origin) {
    // 设置允许跨域的域名
    res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
    // 设置允许的请求方法
    res.setHeader('Access-Control-Allow-Methods''GET, POST, OPTIONS');
    // 设置允许的请求头
    res.setHeader('Access-Control-Allow-Headers''Content-Type');

    res.setHeader('Access-Control-Allow-Credentials'true);
  }

  // 处理预检请求(OPTIONS请求)
  if (req.method === 'OPTIONS') {
    res.writeHead(200);
    res.end();
    return;
  }

  // 处理其他请求
  if (req.url === '/login' && req.method === 'GET') {
    // 设置一个名为 "my-cookie" 的 Cookie,值为 "abc-*",有效期为 1 小时
    res.setHeader(
      'Set-Cookie',
      `my-cookie=abc-${cookieNum++}; Max-Age=3600; HttpOnly; Domain=b.com; SameSite=None; Secure;`
    );
    res.end('Cookie has been set!');
  } else if (req.url === '/getList' && req.method === 'GET') {
    res.end();
  } else {
    res.writeHead(404);
    res.end();
  }
});

server.listen(3001, () => {
  console.log('Server is running on port 3001');
});

可在浏览器查看种完的 Cookie,如下:

7ae75571d860e47aa22ffaf22d4e318f.webp

注:只能种跟接口域名同站的 Cookie,比如 test.b.com/login 接口不能种 Domain=c.com 下的 Cookie。

6c49183be55f7907586adadee969b80e.webp

2.2 Cookie 属性

2.2.1 Expires & Max-Age

两者都可以设置 Cookie 有效期,Max-Age 优先级更高。过期后 Cookie 就不会再跟着请求发送到服务器。也会自动删除 Chrome DevTools -> Application -> Cookies  过期的 Cookie。

2.2.2 Domain

控制 Cookie 在哪些域名下可见可访问,如果指定了一个 Cookie Domain=ele.me,则它与所有的子域名(help.ele.me)共享 Cookie。可以理解为 Cookie 遵守的是「同站」策略。

什么是同站:只要两个 URL 的 eTLD+1 相同即是「同站」,否则就是「跨站」,不需要考虑协议和端口。定义如下:

eTLD: (effective top-level domain) 有效顶级域名,如 .com、.me、.github.io、.top 等

eTLD+1: 有效顶级域名 + 二级域名,如 ele.me,taobao.com

2.2.3 Path

控制 Cookie 在哪些路径下可访问,默认值为 / 也就是所有接口路径都可访问

如:Path=/api/

https://ele.me/api/getList 会携带 Cookie

https://ele.me/abc/getList 不携带 Cookie

2.2.4 HttpOnly

阻止 JavaScript 通过 Document.cookie 属性读写 Cookie。通过document.cookieapi 无法读、写对应的 Cookie

2.2.5 Secure

只有 https 协议(localhost 不受此限制)的请求才会携带 Cookie

2.2.6 SameSite

限制跨站请求不发送 Cookie,这样可以在一定程度上防范跨站请求伪造攻击(CSRF)

Strict(严格): 只发送同站请求的 Cookie,不会发送任何形式的跨站 Cookie

Lax(宽松): 默认值,一般情况下只发送同站 Cookie,有一些特殊情况可以发送跨站 Cookie,需要满足以下条件可以发送跨站 Cookie:

  1. 必须是 GET 或者 HEAD 请求,不能是 POST 请求
  2. 必须是顶级导航请求,可以认为该请求会改变浏览器地址栏 URL,比如通过 a 标签跳转的请求

举例:先在 test.b.com 网站下用 test.b.com/login 接口种 Lax Cookie。然后打开 test.a.com 页面,如下图,该页面有个 a 标签,点击会跳转到 test.b.com,此时会携带 Lax Cookie,但不会携带 Strict Cookie

acc5bb553c8039bae5f94202fcd15e71.webp

None: 跨站和同站请求均发送 Cookie。在设置这个属性值时,必须同时设置 Secure 属性,比如:SameSite=None; Secure

468a3a3837551ee39bccbaa4d6d90a8f.webp

b3ea0f06c9569ddb9444336a863c30f6.webp

SameSite=None + Secure 属性的方式在浏览器禁用三方 Cookie 之前可用,如果浏览器禁用三方 Cookie 需要怎么设置呢?-- 需要配合 Partitioned 属性一起使用

2.2.7 Partitioned

在浏览器禁用三方 Cookie 之前SameSite=None; Secure方式可正常使用,禁用三方 Cookie 后需要配合 Partitioned 属性使用。浏览器开启禁用三方 Cookie 时,set cookie 报错,如下:

38124a769344e3b9fe642e1bfbcc78b3.webp

当 Set Cookie 增加 Partitioned 属性后,Cookie 种成功,如下:

2e7a4e95650b73eb115f52af9357affb.webp

对应域的请求也可以正常携带 Cookie,如下:

40a79b0a8e068b5367b96ccd67917b3d.webp

设置 Partitioned 属性之前

到这里你可能会疑问,为什么要增加 Partitioned 属性?不是多此一举吗?那我们看下之前有什么问题

隐私问题

三方 Cookie 可以跨站跟踪用户的行为,因此可能会泄露用户的个人信息和浏览习惯,比如:用户先访问淘宝,网站会通过 gm.mmstat.com/arms.1.1 接口种一个 sca Cookie,然后用户点击感兴趣的商品也会有 gm.mmstat.com 埋点请求,同时会携带 sca Cookie,如下图:

5a203ee57bd6d24b88314bfd9a7aebbe.webp

之后用户打开天猫,也会携带淘宝网站生成的 sca Cookie,这样 gm.mmstat.com 对应的服务就有能力分析出来用户的行为路径,用户的行为习惯就会被追踪

65413836b72f7ec6c0e0e697ad26bd9f.webp

安全问题

三方 Cookie 可能被黑客利用来进行恶意攻击,比如伪造跨站请求攻击(CSRF),示例如下:

97cf557bd2fa202c43a4174be3b52fa1.webp

加 Partitioned 属性之后

加 Partitioned 属性后,Chrome 内核(从 114 版本开始)的浏览器会对 Cookie 进行分区。如下图,站点 A 内嵌入了站点 C,站点 C 设置了一个带有 Partitioned 属性的 Cookie,这个 Cookie 将保存在一个专门用于站点 A 嵌入 C 时设置的 Cookie 分区中。只有 C 是 A 网站的子应用时才会发送该 Cookie。

这时有个新站点 B,内嵌了站点C,这时 C 站点接口不会携带上面在 A 站点设置的 Cookie

fc04976ce0260ef1273be397a837e88e.webp

如果用户直接访问 C 网站,C 网站的请求不会携带嵌入在 A 中设置的分区 Cookie,这样既能保证当前页面三方 Cookie 的可用性,也能避免上面提到的隐私问题、安全问题。

4c61b28f76976582a3854de3ef141b45.webp

2.3 前端

前端种 Cookie 代码如下:

      
      document.cookie = 'my-js-cookie=abc; Max-Age=3600; Path=/; Domain=b.com; SameSite=None; Secure;'

8c22baeceddf82d1bcc2d96a49e19c9e.webp

局限性

  • 只能种跟当前页面域名同站的 Cookie 比如,在 test.a.com 页面下,document.cookieapi 只能种 Domain=a.com 下的 Cookie,不能种 Domain=b.com 下的 Cookie。

  • 不能重写有 HttpOnly 属性的同名 Cookie 线上故障 Case:某App iOS 端 默认向 webview 容器里种 sid Cookie 作为登录态,并且指定 HttpOnly 属性,但切换账号后容器并没有更新 sid,H5 使用 document.cookie api 也无法重写 sid,导致内嵌的 H5 页面鉴权失败。如果使用后端接口种 Cookie 就没有这个问题。

  • 安全问题,跨站请求伪造攻击(CSRF)

3 浏览器禁用三方 Cookie 计划

3.1 Chrome 禁用三方 Cookie

从 Chrome 114 版本开始,无痕模式默认开启禁用三方 Cookie。

26741d977365dcd594ef78bb12c789ac.webp

9f0430208d6bcdbdfe864a743de14b0b.webp

下面是 Chrome 禁用三方 Cookie 的计划

80a140785c8d33068e802470bd44bd9d.webp

3.2 Safari 禁用三方 Cookie

目前(2023.11.8) Safari 浏览器默认禁用三方 Cookie,也不支持 Partitioned 属性,需要手动设置允许跨站 Cookie 才行,设置入口如下:

9a87d662ba28c6003b198a1f33294f86.webp

3.3 对现有业务影响

只要使用了三方 Cookie 并且没有 Partitioned 属性的业务都会受到影响。

4 三方 Cookie

Cookie Domain 与 页面 URL eTLD+1 不同

eTLD+1: 有效顶级域名 + 二级域名,如 ele.me,taobao.com,如:test.a.com 页面下种了 Domain=b.com Cookie,则是三方 Cookie

请求接口协议与页面协议不同也属于三方 Cookie

如果页面域名和接口域名的 eTLD+1 相同,但页面域名是 http 协议,接口是 https 协议,也属于三方 Cookie

iframe 嵌入的三方子应用

如果嵌入的 iframe 子应用域名与宿主应用域名不是同站,则它是第三方内容,三方网站内使用的 Cookie 都属于三方 Cookie。

如下图,宿主页面(test.a.com)通过 iframe 嵌入子页面(test.b.com),子页面无法设置 Domain=b.com 域下的未分区的 Cookie。

  • a7b60123612aba2b1b21440672c6357d.webp

5 参考

  • https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview#http_%E6%98%AF%E6%97%A0%E7%8A%B6%E6%80%81%EF%BC%8C%E6%9C%89%E4%BC%9A%E8%AF%9D%E7%9A%84
  • https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies
  • https://juejin.cn/post/6926731819903631368?searchId=20231106120717EBA1AB4DB9821BC59D77
  • https://developer.chrome.com/docs/privacy-sandbox/chips/
  • https://developer.chrome.com/blog/cookie-countdown-2023oct/
  • https://developer.chrome.com/docs/privacy-sandbox/third-party-cookie-phase-out/
  • https://web.dev/articles/samesite-cookie-recipes?hl=zh-cn#use_cases_for_cross_site_or_third_party_cookies
浏览 1
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报