最近遇到了不少关于cookie限制的问题,现梳理下现代浏览器Cookie的所有场景和解决办法以此巩固,如有遗漏,欢迎各位大佬补充。
前言
cookie 很多限制其实就是针对跨域和跨站来做的,所以在了解 cookie 限制前,我们要先了解下前置知识。本篇文章主要是针对跨域或者跨站携带cookie的限制,因为同源同站没有任何限制。
跨站
何为跨站?
可以简单理解主域名不相同就是跨站。
什么是主域名?
比如www.baidu.com,baidu.com就是主域名,www是子域名,只要主域名是相同,子域名不管是什么都不会跨站。比如:a.baidu.com 和 www.baidu.com 就是相同站点。需要注意的是,跨站这里并不关心协议和端口号。
那么跨站对Cookie有什么影响?
这就需要先了解下浏览器cookie的 same-site 属性,它的作用就是为了限制跨站发送cookie的。从 chrome 80版本之前,系统会默认在所有环境中发送 Cookie。在80版本之后有两个改变:
- 没有
SameSite属性的 Cookie 被视为SameSite=Lax - 具有
SameSite=None的 Cookie 还必须指定Secure
它有三个值:Strict、Lax、None。
Strict
跨站点时,任何情况下都不会发送 Cookie
Lax
跨站点时,如果是导航GET请求(GET表单、预加载、链接)则可以发送 cookie
None
跨站点时,任何情况下可发送 cookie,但必须同时设置Secure(必须是https请求),否则这条cookie不会生效
小结
其实到这里,我们就大概知道了跨站点的 cookie 限制其实就是浏览器通过 same-site 属性实现的。当你在请求接口时,服务端会设置cookie的same-site属性,在后续请求中这条cookie能否携带取决于 same-site的值。
那么正确的设置了 same-site 属性后,cookie 就一定能携带上吗?答案是不一定,因为 跨域 同样影响 cookie 的携带请继续往下看
跨域
根据浏览器的同源策略:
-
相同的协议
-
相同的主机(host)
-
相同的端口号
上面只要有一个不相同,既是跨域。目前的开发流行前后端分离,这就导致了很大几率会出现接口和前端页面不同源,这就需要后端的同学在响应头中设置 Access-Control-Allow-Origin 属性来允许跨域请求。
当然影响 cookie 的是另一个重要的响应头属性:Access-Control-Allow-Credentials,它决定了在跨域请求中是否携带凭证(其中包括了cookie),也就是说即便cookie正确设置了 same-site 属性,只要服务端没有开放允许跨域请求中携带凭证,你仍然是不能携带cookie的。
那么到这里就完事大吉了吗?别急,还差最后一小步,因为前端也可以控制在跨域请求中是否发送cookie。你需要在发送请求的时候设置,在前端浏览器中发请求一般是使用xhr或者fetch。
xhr - withCredentials
- true - 携带凭证
- false - 不携带凭证
fetch - credentials
- same-origin - 仅同源请求中携带凭证
- include - 在同源和跨域请求中都携带凭证
- omit - 不发送凭证
总结
- 只跨域不跨站 - 首先,我们需要服务端设置 Access-Control-Allow-Credentials:true 响应头。其次,在发送请求的时候我们需要设置请求头 withCredentials 或 credentials 允许跨域请求中携带 cookie。
- 既跨域又跨站 - 在满足第1点条件下,如果是 导航GET请求(GET表单、预加载、链接),则不需要处理。如果是其他方法跨域请求,需要服务端设置 same-site 为None,同时设置Secure,否则这条cookie无法设置成功。