Cookie 是什么
引用 维基百科 里的介绍:
Cookie,类型为“小型文本文件”,指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据。
Cookie 是由服务器发送到浏览器的一小块数据,之后浏览器会保存 Cookie 的值,当再次向同一个服务器发起请求时,会携带之前保存的 Cookie。
Cookie 的表现形式为 <cookie-name>=<cookie-value>;,还可以带上 Path、Expired 等属性,它们之间用 ; 间隔。例如:
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)。
浏览器的同源策略,大家应该都清楚。即两个站点中的协议、域名、端口中的一项不相同,就认为两个站点是非同源的。举个例子:
| oringinA | originB | |
|---|---|---|
| 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 。
举个例子会更清晰一些:
| oringinA | originB | |
|---|---|---|
| https://www.example.com | https://www.evil.com | 跨站: 二级域名不同 |
| https://www.example.co | 跨站: 有效域名不同 | |
| https://a.example.com | 同站 |
| oringinA | originB | |
|---|---|---|
| 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 这个又是大多数开发者需要的一个属性,那么,这个问题该如何解决呢?主要有以下两种方法:
- 设置 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'];
}
- 通过 user-agent,判断是否支持 SameSite=None
在这里可以看到不支持的浏览器。
如果你使用 JavaScript ,可以看看 github.com/linsight/sh…