Cookie & Session & Token 你分清了吗

307 阅读8分钟

Cookie

什么是 cookie?

因为 HTTP 是无状态的,所以为了协助 Web 保持状态,Cookie 因此诞生。在 HTML5 的 localStorage、sessionStorage 出现之前,它作为当时唯一的储存手段也曾一度被用于客户端储存。

cookie机制是采用在客户端保持状态的方案, 浏览器的安装目录下会专门有一个 cookie 文件夹用来存放各个域下设置的cookie。

  • cookie 存储在客户端的纯文本: cookie 由服务器生成,发送给浏览器并保存到某个目录下的文本文件内,在浏览器向同一服务器再次发起请求时自动(添加到请求头) 携带cooike发送到服务器上。
  • cookie 是不可跨域的: 每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的靠的是 domain)

****(浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器)。

Cookie 应用

主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Cookie 属性

Cookie 属性可以理解为 Cookie 的配置项,告诉浏览器 Cookie 的一些额外信息,例如什么时候失效

速查表

Cookie 属性说明类型 : 默认值示例
Domain生效域名, 指定了哪些主机地址可以接收 CookieString: 当前访问地址中的 host 部分scar.site
Path生效路径, 主机下的哪些路径可以接受 Cookie URL 路径必须存在于请求 URL 中String: //docs
Expires过期时间。若 Expires 和 Max-Age 同时存在,Max-Age优先级更高Date: 浏览器会话关闭时间Thu, 22 Jul 2021 00:53:13 GMT
Max-Age有效期,单位秒 在 Cookie 失效之前需要经过的秒数。秒数为 0 或 -1 将会使 cookie 直接过期。Number1000
Secure仅 HTTPS 可用无值,出现即设置
HttpOnly设置了 HttpOnly 属性的 cookie 不能使用 JavaScript 进行访问 如 Document.cookie 、 XMLHttpRequest、 Request APIs、 Cookie Store APIs无值,出现即设置
SameSite允许服务器设定 Cookie 不随着跨站请求一起发送String: Lax值可能性为: Lax Strict None
SameParty允许特定条件跨域共享 Cookie无值,出现即设置
Priority优先级,仅 Chrome 支持- Low:低优先级
  • Medium:默认值,中优先级
  • High:高优先级 | Medium | 值可能性为: Low Medium High |

详细说明

Domain

Domain 属性限制了接收 Cookie 的域名

Set-Cookie: __Secure-ID=123; Secure; Domain=example.com
Expires 时效性

设置过期时间,可以传一个符合 HTTP-Date 格式的值,例如:expires=Mon, 14 Mar 2022 15:39:34 GMT;

如果不设置 Expires,则默认为会话关闭时间;

会话是浏览器的一个概念,一般是一个浏览器 Tab 窗口。

如果浏览器提供了会话恢复功能,恢复回话之时,Cookie 也会一起恢复,就好像会话从来没有关闭一样。

Expires 和 Max-Age 同时存在时,Max-Age优先级更高

HttpOnly

设置cookie是否能通过 js 去访问。

设置了 HttpOnly 属性的 cookie 不能使用 JavaScript 对 Document.cookie 属性、XMLHttpRequest 和 Request APIs、Cookie Store APIs 进行访问。

Secure

标记为 Secure 的 Cookie 只应通过被 HTTPS 协议加密过的请求发送给服务端,因此可以预防 man-in-the-middle 攻击。

但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 固有的不安全性,Secure 标记也无法提供确实的安全保障,例如:可以访问客户端硬盘的人可以读取它。

SameSite

服务器要求某个 Cookie 在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击。

SameSite 可以有下面三种值:

  • None:浏览器会在同站请求、跨站请求下继续发送 Cookies,不区分大小写。
  • Strict:浏览器将只在访问站点与 Cookie 生效的域相同时发送 Cookie。

Lax:新版本浏览器默认设置为 Lax。与 Strict 类似,但是特定条件也可以发送跨域请求:

  • 举个例子,用户从 a.com 跳转到 b.com,URL 发生了变化的同时请求方式为 GET,所以 设置了 Lax的 Cookie 会被发送过去 ,除此之外还有图片加载、iframe 调用等等。
    • URL 必须发生变化
    • HTTP 请求方式必须是安全的,例如 GET、HEAD、OPTIONS,它们不改变数据。
SameSite 和 Domain 的区别

上面提到过,Domain 可以指定 Cookie 生效的域名,那它和 Domain的区别是什么呢?

Domain 属性限制了接收 Cookie 的域名,而 SameSite属性限制了发送 Cookie 的域名

举个例子:

Set-Cookie: Foo=bar; Path=/; Secure; Domain=scar.site;

无论是从 scar.site 还是 foo.example.com 发起的请求,只要被发送到了 scar.site 或者它的子域名,那 Cookie 就能发过去。

Set-Cookie: name=scar; Path=/; Secure; Domain=scar.site;SameSite=strict;

如果设置了 SameSite=strict,那么这个请求只能从 scar.site 发起 Cookie 才能带过去。

Priority

目前只有 Chrome 实现了这个提案

因为 Cookie 有数量限制,所以在 Cookie 超过一定数量时,浏览器会清除最早过期的 Cookie

如果设置了 Priority,Chrome 会先将优先级低的清除,并且每种优先级 Cookie 至少保留一个。可以有下面三种值:

  • Low:低优先级
  • Medium:默认值,中优先级
  • High:高优先级

Cookie 的限制

大小限制

大多数浏览器支持最大为 4KB 的 Cookie,4KB 是针对 Cookie 单条记录的 Value 值。

数量限制

Cookie 有数量限制,而且只允许每个站点存储一定数量的 Cookie,当超过时,最早过期的 Cookie 便被删除。

不同浏览器支持的数量可能不同, 基于 Webkit 内核的是 180 个,基于 gecko 内核的是 150 个,

Session

  • session 是一种记录服务器和客户端会话状态的机制
  • session 是基于 cookie 实现的,session 存储在服务器端,sessionId 会被存储到客户端的cookie 中
  • SessionID 是连接 Cookie 和 Session 的一道桥梁,根据sessionID验证用户的登录状态

当用户打开某个web应用时,便与web服务器产生一次session。服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。

session认证流程

  1. 用户在第一次请求服务器时,服务器创建对应的 session
  2. 请求返回Session 的唯一标识信息 SessionID 返回给浏览器
  3. 浏览器将 sessionID 存入 cookie (同时记录sessionID的域名)
  4. 再次请求服务器时会自动判断 cookie 中是否存在该域名的信息
    1. 若存在,则表明用户已登录,自动携带cookie发送请求,服务端从cookie中获取sessionID,根据sessionID查找对应的session信息
    2. 若不存在,则用户未登录或登录失效

Cookie 和 Session 的区别

  1. 安全性:Session 比 Cookie 安全
    1. session 存储在客户端;
    2. cookie 存储在用户端,容发生篡改
  1. 存取值的类型不同:
    1. Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,
    2. Session 可以存任意数据类型。
  1. 有效期不同:
    1. Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,
    2. Session 一般失效时间较短,客户端关闭或 Session 超时都会失效。
  1. 存储大小不同:
    1. 单个 Cookie 保存的数据不能超过 4K,
    2. Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。

Token (令牌)

Acesss Token

token:访问资源接口(API)时所需要的资源凭证,主要用于对用户身份的验证

简单 token 的组成:

  • uid: 用户唯一的身份标识
  • time: 当前时间的时间戳
  • sign: 签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串

特点:

  • 服务端无状态化、可扩展性好
  • 支持移动端设备
  • 安全
  • 支持跨程序调用

Refresh Token

refresh token 是专用于刷新 access token 的 token。

如果没有 refresh token,也可以刷新 access token,但每次刷新都要用户输入登录用户名与密码,影响用户体验。

而通过 refresh token,客户端直接使用 refresh token 去更新 access token,无需用户进行额外的操作,无感刷新提高用户体验。

  • Access Token 的有效期比较短,当 Acesss Token 由于过期而失效时,使用 Refresh Token 就可以获取到新的 Token,如果 Refresh Token 也失效了,用户就只能重新登录了。
  • Refresh Token 及过期时间是存储在服务器的数据库中,只有在申请新的 Acesss Token 时才会验证,不会对业务接口响应时间造成影响,也不需要向 Session 一样一直保持在内存中以应对大量的请求。

如何获取 Token

  1. 用户登录成功后服务端会返回生成的 token信息
  2. 客户端接收并将token存储在 cookie 或者 vuex 中
  3. 当客户端再次发起请求时在请求拦截时设置请求头携带token信息
  4. 服务端收到请求后验证携带的token信息 获取 userID,如果身份验证成功则返回请求数据

每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里


参考

  1. Session 、Cookie和Token三者的关系和区别