cookie那些事儿

516 阅读4分钟

认识cookie

cookie,记录用户信息或者辨别用户身份的一段数据(通常情况下是加密的),由计算机客户端暂时或者长时间存储。它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。

cookie主要作用使用场景

  • 会话状态管理(如登录状态,购物车信息等
  • 个性化设置(如用户自定义设置,网站主题等)
  • 浏览器行为追踪(如跟踪分析用户行为)

cookie属性

某网上设置的cookie:

完整的cookie应该包含以下几个属性:

  • Name: cookie的名称
  • Value: cookie的值
  • Domain: 使用cookie的域。如果设置主域名如.test.com,那么子域名a.test.com和b.test.com,都可以使用.test.com的cookie。
  • Path: cookie的路径,默认为/,即当前域的所有路径都可以访问cookie。
  • Expires: cookie过期时间。未设置改值,则改cookie为会话型cookie。
  • HttpOnly: 后端通过set-Cookie设置,如果该值为true,则无法通过js来操作cookie。
  • Secure: 安全性,默认为false,标记为Secure的cookie(即值为true),标识cookie的传递确保安全,只能通过https请求发送
  • SameSite: cookie安全性设置。有3个值:Strict/Lax/None。chrome51新增,chrome80+强制执行。(设置了Strict或Lax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。)
    • Strict: 最严格,完全禁止第三方cookie,仅允许发送同站点请求的的cookie。
    • Lax: 规则比Strict稍微宽松,允许部分第三方请求携带cookie。chrome80+默认值
    • None: 任意发送cookie,如果设置SameSite为None,则必须同时设置Secure,否则不成效。意味着网站必须采用https。
  • Priority: 优先级,chrome的提案,三种优先级,Low/Medium/High,当cookie数量超出时,低优先级的cookie会被优先清除(仅仅chrome的提案,非标准方案)

从 Chrome 52 和 Firefox 52 开始,不安全的站点(http:)无法使用Cookie的 Secure 标记。
从 Chrome 80 开始,SameSite默认值为Lax,即使没有设置SameSite,也按照Lax的规则执行。

cookie的设置

后端

服务器使用Set-Cookie,在Respons Headers里面发送cookie,客服端接收到之后,根据设置来保存cookie。

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: happy=everyday
Set-Cookie: study=everyday

以Nodejs为例

const server = http.createServer((req, res) => {
  res.setHeader('Set-Cookie', ['happy=everyday', 'study=everyday']);
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('ok');
});	

前端

    document.cookie = 'study=everyday'  

需要特别注意的是,前端设置cookie,需要确认当前运行环境与设置cookie的domain是否为同一站点。(即主域相同)。 前端设置cookie,无法跨域设置别的站点的cookie。

// set cookie
// www.baidu.com
document.cookie = 'study=everyday; domain=www.baidu.com' // 设置成功
// www.baidu.com
document.cookie = 'study=everyday; domain=baidu.com' // 设置成功
// www.baidu.com
document.cookie = 'study=everyday; domain=www.taobao.com' // 设置失败
// www.baidu.com
document.cookie = 'study=everyday; domain=taobao.com' // 设置失败

后端设置cookie,通过Set-Cookie的方式可以设置cookie的所有属性值
前端设置cookie,无法设置HttpOnly属性,并且Secure属性设置的时候,必须保证是https的网页才能进行设置(http本身是不安全的,也就无法去保证cookie的安全)

cookie的传递

场景: 当一个前端页面,向服务端请求资源的时候,可能会遇到三个情况。向静态资源服务器请求图片等cdn加速的资源;向api接口请求数据资源;想第三方埋点平台请求埋点情况。我们假设,当前页面的域名和接口域名相同,为page.baidu.com, 静态资源服务器地址为static.baidu.com,数据埋点的地址为report.maidian.com,因次,三种情况分别是同域名,同主域不同子域,完全跨域。

同域名

这种情况下,cookie只要设置成功,在未失效的前提下,自动在浏览器端和服务端进行传递。不用做任何处理。

同主域不同子域

这种情况,需要进行设置domain,如果不设置,或者设置成子域名,则也无法进行cookie的传递

// page.baidu.com
document.cookie = 'study=everyday; domain=static.baidu.com' // 无法传递cookie
// page.baidu.com
document.cookie = 'study=everyday; domain=baidu.com' // 可以传递cookie

完全跨域

这种情况前后端都要进行处理

// 前端(axios为例)
axios.defaults.withCredentials = true; // ajax请求中,打开withCredentials属性


// 后端(nodjs为例)
const server = http.createServer((req, res) => {
  res.setHeader('Access-Control-Allow-Credentials', true);
  res.setHeader('Access-Control-Allow-Origin', req.getHeader('Origin'));
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('ok');
});	

你以为到此完事了,并没有。随着浏览器开始限制甚至禁止第三方cookie。上面的设置已经无法满足需求了。还是无法携带cookie。需要额外对cookie进行设置。

// set cookie
const server = http.createServer((req, res) => {
  res.setHeader('Set-Cookie', ['happy=everyday; SameSite=None; Secure']);
  res.setHeader('Access-Control-Allow-Credentials', true);
  res.setHeader('Access-Control-Allow-Origin', req.getHeader('Origin'));
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('ok');
});	

cookie安全

关于cookie的安全,有位大神总结的很好,大家可以参考,本文不再叙述。
当浏览器全面禁用三方Cookie

还有MDN上面的解释 developer.mozilla.org/en-US/docs/…

本文参考链接

web.dev/samesite-co…
www.ruanyifeng.com/blog/2019/0…
developer.mozilla.org/en-US/docs/…