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 | 生效域名, 指定了哪些主机地址可以接收 Cookie | String: 当前访问地址中的 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 直接过期。 | Number | 1000 |
| 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认证流程
- 用户在第一次请求服务器时,服务器创建对应的 session
- 请求返回Session 的唯一标识信息 SessionID 返回给浏览器
- 浏览器将 sessionID 存入 cookie (同时记录sessionID的域名)
- 再次请求服务器时会自动判断 cookie 中是否存在该域名的信息
-
- 若存在,则表明用户已登录,自动携带cookie发送请求,服务端从cookie中获取sessionID,根据sessionID查找对应的session信息
- 若不存在,则用户未登录或登录失效
Cookie 和 Session 的区别
- 安全性:Session 比 Cookie 安全,
-
- session 存储在客户端;
- cookie 存储在用户端,容发生篡改
- 存取值的类型不同:
-
- Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,
- Session 可以存任意数据类型。
- 有效期不同:
-
- Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,
- Session 一般失效时间较短,客户端关闭或 Session 超时都会失效。
- 存储大小不同:
-
- 单个 Cookie 保存的数据不能超过 4K,
- 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
- 用户登录成功后服务端会返回生成的 token信息
- 客户端接收并将token存储在 cookie 或者 vuex 中
- 当客户端再次发起请求时在请求拦截时设置请求头携带token信息
- 服务端收到请求后验证携带的token信息 获取 userID,如果身份验证成功则返回请求数据
每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里