做一个真正懂cookie的前端

8,501 阅读5分钟

在前端的知识领域,cookie 是个很基础的东西,但真正对 cookie 有全面了解的恐怕不多。现在让我们一起劣实基础,更加全面了解其吧。

cookie的诞生

我们知道 http 是无状态的,这是指对于同一请求,只要请求参数相同,http 无法知道是哪个客户端发出的请求,也无法判断是否为已登录用户请求,这就导致了 http 无法记住用户的登录状态。所以 cookie 设计的初衷就是为了弥补 http 的无状态,帮助记录客户端的用户状态,作为用户登录凭证的载体。

通过服务器为登录用户设置 cookie 来保存当前的用户状态,每次请求时浏览器自动携带该域名下的 cookie 来告诉服务器当前请求的用户ID,与服务器的用户 sessionID 相匹配,从而确定当前用户及登录状态。

cookie的相关操作

设置cookie

通过JS设置

// 一次只能设置一对键值,但不像传统的JS一般,不会覆盖
document.cookie = 'name=xxx;';

服务端设置(node)

res.setHeader('Set-Cookie', 'name=xxx;');

修改cookie

修改 cookie 直接覆盖就行

document.cookie = 'name=xxx;';

删除cookie

设置过期时间为过去时间

document.cookie = 'name=xxx;expires=' + new Date('1999');

cookie 相关属性

expires

其值为时间字符串,用于设置过期时间,可设置过去时间才删除 cookie

document.cookie = 'name=xxx;expires=' + new Date('1999');

domain

domain 设置哪些网站可以接受 cookie,默认为 origin(其中 domain 须为当前请求(网页)域名或者主域,否则无效)

document.cookie = 'name=xxx;domain=a.xxx.com';

path

path 标识指定了主机下的哪些路径可以接受 cookie,默认为 /,其中 path 须存在于当前请求(网页)路径中

document.cookie = 'name=xxx;path=/xxx;';

Secure

标记为 Secure 的 cookie 限制只能在 https 中设置与传输。

// 如果在 http 下的网页中设置则不生效
document.cookie = 'name=xxx;Secure';

HttpOnly

设置 cookie 只能被请求携带,不能被 JS 访问,可以减少 xss 攻击,该属性只能在服务的设置。

res.setHeader('Set-Cookie', 'name=xxx;HttpOnly;');

SameSite

SameSite 可以设置为以下几个值

  • none (旧 chrome 版本(80以下)默认规则)

浏览器会在同站请求、跨站请求下继续发送 cookies,不区分大小写

  • Strict

浏览器将只在访问相同站点时发送 cookie。

  • Lax (新 chrome 版本默认规则)

规则稍稍放宽,大多数情况也是不发送第三方 cookie,但是导航到目标网址的 get 请求除外。

导航到目标网址的 get 请求,只包括三种情况:链接,预加载请求,get 表单。详见下表。

请求类型示例正常情况Lax
链接<a href="..."></a>发送 Cookie发送 Cookie
预加载<link rel="prerender" href="..."/>发送 Cookie 发送Cookie
GET 表单<form method="GET" action="...">发送 Cookie 发送Cookie
POST 表单<form method="POST" action="...">发送 Cookie不发送
iframe<iframe src="..."></iframe>发送 Cookie不发送
AJAX$.get("...")发送 Cookie不发送
Image<img src="...">发送 Cookie不发送

设置为 Lax 和 Strict 可以杜绝很多 csrf 攻击

cookie 相关知识概念

请求自动携带

在浏览器中(老版本),请求(包括 get 和 post)会自动携带请求地址(服务器所在域名,注意不是发起请求所在的网页域名)的 cookie,跨域的 ajax 需要配置 withCredentials 。而在新版本浏览器上(chrome 80以上),因为 SameSite 的默认值为 Lax,所以跨域请求携带 cookie 被限制了,将不再可以携带配置为 Lax 的跨域 cookie。

生命周期

cookie 的生命周期默认为 session,即浏览器关闭后删除。如果设置了 expires,则由 expires 控制,如果浏览器关闭还没到过期时间,则会保存在硬盘中。

cookie 与 session 的区别

session 是服务端的一种机制,使用类似散列表的数据结构来保存用于用户信息,如登录状态。

cookie 则可以用于服务端保存登录状态,比如为客户端设置 cookie 来保存 session 对应的 sessionID,下次请求时客户端自动携带 cookie,服务的从中取出 sessionID,在从 session 表中获取用户登录状态及用户信息。

cookie 和 token 的关系

token 是另一种流行的处理 http 无状态的方式,一般设置在请求头中。当用户登录成功时返回 token 给客户端,客户端再次请求时携带 token,服务端获取 token 后,再从 session 中获取用户信息及登录状态。

与 cookie 相比,因为 token 在代码中设置,不会在访问第三方网站时携带 cookie,可以有效避免 csrf 攻击。

cookie缺点

  • cookie 的大小一般被浏览器限制为 4kb

  • 请求自动携带 cookie 其实会造成无效的带宽浪费

  • 安全问题(csrf 与 xss)

总结

cookie 曾经是被各个网站使用的流行机制,但是随着 token 机制的运用及 html5 存储的兴起,其实已经有很多网站不再使用 cookie。但不管怎样,cookie 还是有很多独特运用场景的,作为前端还是有必要去学习及了解的。如果本文有错误的地方,欢迎大家纠正。

参考


欢迎来前端学习打卡群一起学习~516913974