浅谈 Cookie

140 阅读3分钟

最近遇到了不少关于cookie限制的问题,现梳理下现代浏览器Cookie的所有场景和解决办法以此巩固,如有遗漏,欢迎各位大佬补充。

前言

cookie 很多限制其实就是针对跨域和跨站来做的,所以在了解 cookie 限制前,我们要先了解下前置知识。本篇文章主要是针对跨域或者跨站携带cookie的限制,因为同源同站没有任何限制。

跨站

何为跨站?

可以简单理解主域名不相同就是跨站。

什么是主域名?

比如www.baidu.combaidu.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 - 不发送凭证

总结

  1. 只跨域不跨站 - 首先,我们需要服务端设置 Access-Control-Allow-Credentials:true 响应头。其次,在发送请求的时候我们需要设置请求头 withCredentialscredentials 允许跨域请求中携带 cookie。
  2. 既跨域又跨站 - 在满足第1点条件下,如果是 导航GET请求(GET表单、预加载、链接),则不需要处理。如果是其他方法跨域请求,需要服务端设置 same-site 为None,同时设置Secure,否则这条cookie无法设置成功