Cookie 的 SameSite 属性

486 阅读3分钟

Cookie 是什么

引用 维基百科 里的介绍:

Cookie,类型为“小型文本文件”,指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据。

Cookie 是由服务器发送到浏览器的一小块数据,之后浏览器会保存 Cookie 的值,当再次向同一个服务器发起请求时,会携带之前保存的 Cookie

Cookie 的表现形式为 <cookie-name>=<cookie-value>;,还可以带上 PathExpired 等属性,它们之间用 ; 间隔。例如:

Cookie: name=laohan; Path=/; Expires=Thu, 31 Dec 2020 15:59:59 GMT;

更多详细的介绍可以参考这里 Using HTTP cookies

SameSite 属性

Cookie 主要有 Domain、Path、Expires、Secure、HttpOnly 等属性,作为一个 web 开发者,相信应该不会感到陌生。今天主要介绍的是 Cookie 中的大家可能不怎么熟悉 SameSite 属性。

SameSite 可接收以下三个值

  • Strict
  • Lax
  • None

对于不同的值,会有不同的表现。

介绍之前,先了解一个概念:跨站(cross-site)

浏览器的同源策略,大家应该都清楚。即两个站点中的协议、域名、端口中的一项不相同,就认为两个站点是非同源的。举个例子:

oringinAoriginB
https://www.example.com:443 http://www.example.com:443 非同源: 协议不同
https://a.example.com:443 非同源: 域名不同
https://www.example.com:80 非同源: 端口不同
https://www.example.com:443 同源

那么,跨站又是指什么呢?

对应跨站,那应该也有同站的概念。如果两个站点不属于同站,那就是跨站了嘛。

相比较于同源,同站会更简单。并不要求协议、域名和端口都要一致,只要 eTLD + 1 一致就可以了。

Top-Level-Domain(TLD) 即顶级域名,例如 .com、.org 等。我们所说的 “站” 就是 domain + TLD 组成的部分。当两个站点的 “站” 相同时,我们就可以认为两个站属于同站。 但对于 .github.io 这样的站点,使用 .io 并不足以识别 “站”,需要引入 effective TLDS,即有效的顶级域名。

所以两个站点同站的条件是 eTLD + 1 相等。对于 www.example.com 来说,eTLD + 1 就是 example.com。对于 a.b.github.io 来说,eTLD + 1 就是 b.github.io 。

举个例子会更清晰一些:

oringinAoriginB
https://www.example.com https://www.evil.com 跨站: 二级域名不同
https://www.example.co 跨站: 有效域名不同
https://a.example.com 同站
oringinAoriginB
https://example.github.io https://evil.github.io 跨站: 三级域名不同
https://www.example.com 跨站: 有效域名不同
https://a.example.github.io 同站

Strict

当跨站时,发送请求不会带上 Cookie。仅当与当前页面属于同个站点时,才会携带 Cookie。

Lax

允许部分跨站请求携带 Cookie。但仅在以下几种情况

请求类型示例是否发送
链接<a href="xxx"></a>
预加载<link rel="prerender" href="xxx" />
GET 表单<form method="GET" action="xxx">

<img>、<script>加载资源时都不允许携带 Cookie

None

允许任意站点请求携带 Cookie。但是需要额外带上 Secure 属性。

由于这个值是在之后新添加进来,设置 SameSite=None 对于一些浏览器会存在兼容问题,不同的浏览器表现也不一致。有一些浏览器会忽略设置的值,有一些则会认为是 SameSite=Strict 。

但是对于 SameSite=None 这个又是大多数开发者需要的一个属性,那么,这个问题该如何解决呢?主要有以下两种方法:

  1. 设置 Cookie 时,设置 2 次
// express

// 设置
res.cookie('3pcookie', 'value', { sameSite: 'none', secure: true });
res.cookie('3pcookie-legacy', 'value', { secure: true });

// 取值
  if (req.cookies['3pcookie']) {
    cookieVal = req.cookies['3pcookie'];
  } else if (req.cookies['3pcookie-legacy']) {
    cookieVal = req.cookies['3pcookie-legacy'];
  }
  1. 通过 user-agent,判断是否支持 SameSite=None

这里可以看到不支持的浏览器。

如果你使用 JavaScript ,可以看看 github.com/linsight/sh…

参考

原文

原文地址