0%

Cookie、Session、Token、JWT

文章 https://zhuanlan.zhihu.com/p/164696755 的学习笔记

Cookie是不可跨域的,每个Cookie都会绑定单一的域名,但一级域名和二级域名之间是允许共享使用的(利用domain字段)

img

注意事项

  • 因为存储在客户端,容易被客户端篡改,使用前需要验证合法性
  • 不要存储敏感数据,比如用户密码,账户余额
  • 使用 httpOnly 在一定程度上提高安全性
  • 尽量减少 Cookie 的体积,能存储的数据量不能超过 4kb
  • 设置正确的 domain 和 path,减少数据传输
  • Cookie 无法跨域
  • 一个浏览器针对一个网站最多存 20 个Cookie,浏览器一般只允许存放 300 个Cookie
  • 移动端对 Cookie 的支持不是很好,而 Session 需要基于 Cookie 实现,所以移动端常用的是 Token

Session

Session是基于Cookie实现的,Session存储在服务器端的内存中,SessionId 会被存储到客户端的Cookie中

.img

根据以上流程可知,SessionID 是连接 Cookie 和 Session 的一道桥梁

注意事项

  • 将 Session 存储在服务器里面,当用户同时在线量比较多时,这些 Session 会占据较多的内存,服务器需要定期清理过期的 Session
  • 当网站采用集群部署的时候,会遇到多台 Web 服务器之间 Session 不共享的问题,这里就不展开了
  • 当多个应用要共享 Session 时,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好Cookie的跨域处理
  • SessionId 是存储在 Cookie 中的,假如浏览器不支持 Cookie 怎么办? 一般会把 SessionId 跟在 URL 参数后面即重写URL,所以 Session 不一定非得需要靠 Cookie 实现
  • 移动端对 Cookie 的支持不是很好,而 Session 需要基于 Cookie 实现,所以移动端常用的是 token
  • 安全性: Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的
  • 存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型
  • 有效期不同: Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效
  • 存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源

Token

Acesss Token

  • 访问API时所需要的资源凭证

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

  • 特点:

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

.img

  • 基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
  • token 完全由应用管理,所以它可以避开同源策略(???)

Refresh Token

Refresh Token 是专用于刷新 Access Token 的 Token。如果没有 refresh token,也可以刷新 access token,但每次刷新都要用户输入登录用户名与密码,会很麻烦。有了 refresh token,可以减少这个麻烦,客户端直接用 refresh token 去更新 access token,无需用户进行额外的操作

.img

Refresh Token 及过期时间存储在服务器的数据库中,只有在申请新的 Acesss Token 时才会验证,不会对业务接口响应时间造成影响,也不需要像 Session 一样一直保持在内存中以应对大量的请求

注意事项

  • 如果你认为用数据库来存储 Token 会导致查询时间太长,可以选择放在内存当中。比如 Redis 很适合对 Token 查询的需求
  • Token 完全由应用管理,所以它可以避开同源策略
  • Token 可以避免 CSRF 攻击(因为不需要 cookie 了)

Token 和 Session 的区别

  • Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化

    Token 是令牌访问API时所需要的资源凭证,使服务端无状态化

  • Session 和 Token 并不矛盾,作为身份认证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重放攻击,而 Session 就必须依赖链路层来保障通讯安全了。如果需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态

  • 所谓 Session 认证只是简单的把 User 信息存储到 Session 里,因为 SessionID 的不可预测性,暂且认为是安全的

    而 Token ,如果指的是 OAuth Token 或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对 App 。其目的是让某 App 有权利访问某用户的信息。这里的 Token 是唯一的,不可以转移到其它 App上,也不可以转到其它用户上

    Session 只提供一种简单的认证,即只要有此 SessionID ,即认为有此 User 的全部权利。是需要严格保密的,这个数据应该只保存在服务器,不应该共享给其它网站或者第三方 App

    所以简单来说:如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token 。如果永远只是自己的网站,自己的 App,用什么就无所谓了

JWT

Json Web Token,是目前最流行的跨域认证解决方案

  • JWT 是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准(RFC 7519)

    JWT 一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,比如用在用户登录上

  • 可以使用 HMAC 算法或者是 RSA 的公/私秘钥对 JWT 进行签名,增强安全性

认证流程👇

.img

  • 因为 JWT 是自包含的(内部包含了一些会话信息),因此减少了需要查询数据库的需要
  • 因为 JWT 并不使用 Cookie ,所以你可以使用任何域名提供你的 API 服务(CORS, Cross-Origin Resource Sharing, 跨域资源共享)

前后端有三种传递JWT的方式:

  • 在请求头的 Authorization 字段中使用Bearer 模式添加:Authorization: Bearer <token>
  • 在POST请求的body里携带
  • 在URL中携带:http://www.example.com/user?token=xxx

注意事项

  • JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次

  • JWT 不加密的情况下,不能将秘密数据写入 JWT

  • JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数

  • JWT 最大的优势是服务器不再需要存储 Session,使得服务器认证鉴权业务可以方便扩展

    但这也是 JWT 最大的缺点:由于服务器不需要存储 Session 状态,因此使用过程中无法废弃某个 Token 或者更改 Token 的权限。也就是说一旦 JWT 签发了,到期之前就会始终有效,除非服务器部署额外的逻辑

  • JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证

  • JWT 适合一次性的命令认证,颁发一个有效期极短的 JWT,即使暴露了危险也很小,由于每次操作都会生成新的 JWT,因此也没必要保存 JWT,真正实现无状态

Token 和 JWT 的区别

  • Token:服务端验证客户端发送过来的 Token 时,还需要查询数据库获取用户信息,然后验证 Token 是否有效
  • JWT:将 Token 和 Payload 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据

PS: 三种认证授权方案

  • Session+Cookie
  • Token (如 JWT, SSO)
  • OAuth 2.0