彻底搞懂 Cookie、Session、Token...

参考:彻底搞懂 Cookie、Session、Token、JWT - 简书

目录

1. 什么是cookie?

2. 什么是session?

3. Cookie 和 Session 的区别:

4. 什么是token(令牌)?

Acesss Token

Refresh Token

5. Token 和 Session 的区别:

6. 常见问题

7. 分布式架构下 session 共享方案



1. 什么是cookie?

因为http是“无状态”的协议(对于事务处理没有记忆能力,每次客户端和服务端通信会话完成后,服务端不会保存任何会话信息)。也就是每个http请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法关联上一次请求发送者和本次发送者是否是同一个人。所以服务器和浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动去维护一个状态,这个状态用于告知服务端前后两个请求是否来自于同一个浏览器。而这个状态就需要通过cookie/session去实现。参考:

  • cookie存储在客户端:cookie是服务器发送到用户浏览器并保存在本地的一小块"文本数据",他会在浏览器下次向同一服务器再发起请求时被携带并发送给服务器。

  • cookie不可跨域:每个cookie都会绑定单一域名,无法在其他域名下获取使用,一级和二级域名之间是允许共享使用的(依靠cookie属性中的domain字段)

2. 什么是session?

session是另一种记录服务端和客户端会话状态的机制

  • session是基于cookie实现的,session存储在服务端,sessionId会被存储到客户端的cookie中

session 认证流程:

  • 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session

  • 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器

  • 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名

  • 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。

根据以上流程可知,SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。

3. Cookie 和 Session 的区别:

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

4. 什么是token(令牌)?

Acesss Token

访问资源接口(API)时所需要的资源凭证。

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

特点:

  • 服务端无状态化,可扩展性好

  • 支持移动端设备

  • 安全

  • 支持跨程序调用

token的身份验证流程:

  • 客户端使用用户名跟密码请求登录

  • 服务端收到请求,去验证用户名与密码

  • 验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端

  • 客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里

  • 客户端每次向服务端请求资源的时候需要带着服务端签发的 token

  • 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据

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

基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。

服务端用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库。

token 完全由应用管理,所以它可以避开同源策略。

Refresh Token

另外一种 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 一样一直保持在内存中以应对大量的请求。(至于Refresh Token的过期时间,也应该是在解析数字签名的时间戳时,业务逻辑去验证其是否已过期

5. Token 和 Session 的区别:

Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。

Session 和 Token 并不矛盾,作为身份认证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重放攻击(签名中包含当前时间戳的timestamp字段,时间每刻都是不断刷新的,因此每时每刻的Token值都不同,可以避免攻击者发送一个目的主机已接收过的包,来达到欺骗系统进行身份认证的目的),而 Session 就必须依赖链路层来保障通讯安全了。如果你需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态。

所谓 Session 认证只是简单的把 User 信息存储到 Session 里,因为 SessionID 的不可预测性,暂且认为是安全的。而 Token ,如果指的是 OAuth Token 或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对 App 。其目的是让某 App 有权利访问某用户的信息。这里的 Token 是唯一的。不可以转移到其它 App上,也不可以转到其它用户上。Session 只提供一种简单的认证,即只要有此 SessionID ,即认为有此 User 的全部权利。是需要严格保密的,这个数据应该只保存在站方,不应该共享给其它网站或者第三方 App。所以简单来说:如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token 。如果永远只是自己的网站,自己的 App,用什么就无所谓了。

6. 常见问题

使用 cookie 时需要考虑的问题:

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

使用 session 时需要考虑的问题:

  • 将 session 存储在服务器里面,当用户同时在线量比较多时,这些 session 会占据较多的内存,需要在服务端定期的去清理过期的 session
  • 当网站采用集群部署的时候,会遇到多台 web 服务器之间如何做 session 共享的问题。因为 session 是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建 session 的服务器,那么该服务器就无法拿到之前已经放入到 session 中的登录凭证之类的信息了。
  • 当多个应用要共享 session 时,除了以上问题,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好 cookie 跨域的处理。
  • sessionId 是存储在 cookie 中的,假如浏览器禁止 cookie 或不支持 cookie 怎么办? 一般会把 sessionId 跟在 url 参数后面即重写 url,所以 session 不一定非得需要靠 cookie 实现
  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

使用 token 时需要考虑的问题:

  • 如果你认为用数据库来存储 token 会导致查询时间太长,可以选择放在内存当中。比如 redis 很适合你对 token 查询的需求。
  • token 完全由应用管理,所以它可以避开同源策略
  • token 可以避免 CSRF 攻击(因为不需要 cookie 了)
  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

使用加密算法时需要考虑的问题:

  • 绝不要以明文存储密码
  • 永远使用 哈希算法 来处理密码,绝不要使用 Base64 或其他编码方式来存储密码,这和以明文存储密码是一样的,使用哈希,而不要使用编码。编码以及加密,都是双向的过程,而密码是保密的,应该只被它的所有者知道, 这个过程必须是单向的。哈希正是用于做这个的,从来没有解哈希这种说法, 但是编码就存在解码,加密就存在解密。
  • 绝不要使用弱哈希或已被破解的哈希算法,像 MD5 或 SHA1 ,只使用强密码哈希算法。
  • 绝不要以明文形式显示或发送密码,即使是对密码的所有者也应该这样。如果你需要 “忘记密码” 的功能,可以随机生成一个新的 一次性的(这点很重要)密码,然后把这个密码发送给用户。

7. 分布式架构下 session 共享方案

session 复制:

任何一个服务器上的 session 发生改变(增删改),该节点会把这个 session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 session ,以此来保证 session 同步

  • 优点: 可容错,各个服务器间 session 能够实时响应。

  • 缺点: 会对网络负荷造成一定压力,如果 session 量大的话可能会造成网络堵塞,拖慢服务器性能。

session 共享(常用):

使用分布式缓存方案比如 Memcached 、Redis 来缓存 session,但是要求 Memcached 或 Redis 必须是集群

把 session 放到 Redis 中存储,虽然架构上变得复杂,并且需要多访问一次 Redis ,但是这种方案带来的好处也是很大的:

实现了 session 共享

  • 可以水平扩展(增加 Redis 服务器)

  • 服务器重启 session 不丢失(不过也要注意 session 在 Redis 中的刷新/失效机制)

  • 不仅可以跨服务器 session 共享,甚至可以跨平台(例如网页端和 APP 端)

session 持久化:

将 session 存储到数据库中,保证 session 的持久化

  • 优点: 服务器出现问题,session 不会丢失

  • 缺点: 如果网站的访问量很大,把 session 存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值