jwt花间独酌

Cookie、Session、Token与JWT解析

2021-06-24  本文已影响0人  _code_x

认证、授权与凭证

什么是认证(Authentication)?

什么是授权(Authorization)?

什么是凭证(Credentials)

Cookie与Session

什么是Cookie?

cookie 重要的属性

什么是 Session

session 认证流程(如上图):

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

基于Session的认证机制由Servlet规范定制,Servlet容器已经实现,用户通过HttpSession的操作方法可以实现:

Cookie 和 Session 的区别

拓展:Session痛点

看起来通过 cookie + session 的方式是解决了问题, 但是我们忽略了一个问题,上述情况能正常工作是因为我们假设 server 是单机工作的,但实际在生产上,为了保障高可用,一般服务器至少需要两台机器,通过负载均衡的方式来决定到底请求该打到哪台机器上。

假设登录请求打到了 A 机器,A 机器生成了 session 并在 cookie 里添加 sessionId 返回给了浏览器,那么问题来了:下次添加购物车时如果请求打到了 B 或者 C,由于 session 是在 A 机器生成的,此时的 B,C 是找不到 session 的,那么就会发生无法添加购物车的错误,就得重新登录了,此时请问该怎么办。主要有以下三种方式:

(1 )session 复制

A 生成 session 后复制到 B, C,这样每台机器都有一份 session,无论添加购物车的请求打到哪台机器,由于 session 都能找到,故不会有问题

这种方式虽然可行,但缺点也很明显:

(2)session 粘连

这种方式是让每个客户端请求只打到固定的一台机器上,比如浏览器登录请求打到 A 机器后,后续所有的添加购物车请求也都打到 A 机器上,Nginx 的 sticky 模块可以支持这种方式,支持按 ip 或 cookie 粘连等等,如按 ip 粘连方式如下

这样的话每个 client 请求到达 Nginx 后,只要它的 ip 不变,根据 ip hash 算出来的值会打到固定的机器上,也就不存在 session 找不到的问题了,当然不难看出这种方式缺点也是很明显,对应的机器挂了怎么办?

(3)session 共享

这种方式也是目前各大公司普遍采用的方案,将 session 保存在 redis,memcached 等中间件中,请求到来时,各个机器去这些中间件取一下 session 即可。

缺点其实也不难发现,就是每个请求都要去 redis 取一下 session,多了一次内部连接,消耗了一点性能,另外为了保证 redis 的高可用,必须做集群,当然了对于大公司来说, redis 集群基本都会部署,所以这方案可以说是大公司的首选了。

Token(令牌)与 JWT(跨域认证)

Token概述(no session!)

通过上文分析我们知道通过在服务端共享 session 的方式可以完成用户的身份定位,但是不难发现也有一个小小的瑕疵:搞个校验机制我还得搭个 redis 集群?大厂确实 redis 用得比较普遍,但对于小厂来说可能它的业务量还未达到用 redis 的程度,所以有没有其他不用 server 存储 session 的用户身份校验机制呢,使用token!

简单来说:首先请求方输入自己的用户名,密码,然后 server 据此生成 token,客户端拿到 token 后会保存到本地(token存储在浏览器端),之后向 server 请求时在请求头带上此 token 即可(server有校验机制,检验token合法性,同时server通过token中携带的uid确定是谁在访问它)。

可以看到 token 主要由三部分组成:

当 server 收到浏览器传过来的 token 时,它会首先取出 token 中的 header + payload,根据密钥生成签名,然后再与 token 中的签名比对,如果成功则说明签名是合法的,即 token 是合法的。而且你会发现 payload 中存有我们的 userId,所以拿到 token 后直接在 payload 中就可获取 userid,避免了像 session 那样要从 redis 去取的开销。

你会发现这种方式确实很妙,只要 server 保证密钥不泄露,那么生成的 token 就是安全的,因为如果伪造 token 的话在签名验证环节是无法通过的,就此即可判定 token 非法。

可以看到通过这种方式有效地避免了 token 必须保存在 server 的弊端,实现了分布式存储,不过需要注意的是,token 一旦由 server 生成,它就是有效的,直到过期,无法让 token 失效,除非在 server 为 token 设立一个黑名单,在校验 token 前先过一遍此黑名单,如果在黑名单里则此 token 失效,但一旦这样做的话,那就意味着黑名单就必须保存在 server,这又回到了 session 的模式,那直接用 session 不香吗。所以一般的做法是当客户端登出要让 token 失效时,直接在本地移除 token 即可,下次登录重新生成 token 就好。

另外需要注意的是 token 一般是放在 header 的 Authorization 自定义头里,不是放在 Cookie 里的,这主要是为了解决跨域不能共享 Cookie 的问题

总结:token解决什么问题(为什么要用token)?

拓展1:那啥是CSRF呢?

攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过(cookie 里带来 sessionId 等身份认证的信息),所以被访问的网站会认为是真正的用户操作而去运行。

那么如果正常的用户误点了上面这张图片,由于相同域名的请求会自动带上 cookie,而 cookie 里带有正常登录用户的 sessionid,类似上面这样的转账操作在 server 就会成功,会造成极大的安全风险

CSRF 攻击的根本原因在于对于同样域名的每个请求来说,它的 cookie 都会被自动带上,这个是浏览器的机制决定的!

至于完成一次CSRF攻击必要的两个步骤:

1、首先登了一个正常的网站A,并且在本地生成了cookie
2、在cookie有效时间内,访问了危险网站B(就获取了身份信息)

Q:那我不访问危险网站就完了呗?
A:危险网站也许只是个存在漏洞的可信任网站!

Q:那我访问完正常网站,关了浏览器就好了呀?
A:即使关闭浏览器,cookie也不保证一定立即失效,而且关闭浏览器并不能结束会话,session的生命周期跟这些都没关系。

拓展2:同源策略?

拓展3:什么是跨域,如何解决?

拓展4:易于扩展?

拓展5:无状态?

拓展6:什么是单点登录?

Acesss Token

特点:

token 的身份验证流程:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
  4. 客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据

注意点

Refresh Token

两者区别

Token 的缺点

那有人就问了,既然 token 这么好,那为什么各个大公司几乎都采用共享 session 的方式呢,可能很多人是第一次听到 token,token 不香吗? token 有以下两点劣势:

所以 token 更适合一次性的命令认证,设置一个比较短的有效期!!!

拓展:不管是 cookie 还是 token,从存储角度来看其实都不安全(实际上防护 CSRF 攻击的正确方式是用 CSRF token),都有暴露的风险,我们所说的安全更多的是强调传输中的安全,可以用 HTTPS 协议来传输, 这样的话请求头都能被加密,也就保证了传输中的安全。

其实我们把 cookie 和 token 比较本身就不合理,一个是存储方式,一个是验证方式,正确的比较应该是 session vs token。

Token 和 Session 的区别

token和session其实都是为了身份验证,session一般翻译为会话,而token更多的时候是翻译为令牌;session和token都是有过期时间一说,都需要去管理过期时间;

JWT概述

生成 JWT

JWT 的原理

JWT 认证流程:

Authorization: Bearer <token>

JWT 的使用方式

方式一

GET /calendar/v1/events

方式二

方式三

http://www.example.com/user?token=xxx

项目中使用 JWT

项目地址:https://github.com/yjdjiayou/jwt-demo

Token 和 JWT 的区别

相同:

区别:

常见的前后端鉴权方式

  1. Session-Cookie

  2. Token 验证(包括 JWT,SSO)

  3. OAuth2.0(开放授权)

常见的加密算法

不可逆加密:【Hash加密算法/散列算法/摘要算法】

MD5:Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。该算法的文件号为RFC 1321(R.Rivest,MIT Laboratory for Computer Science and RSA Data Security Inc. April 1992)。 MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。

MD5算法具有以下特点: 1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。 2、容易计算:从原数据计算出MD5值很容易。 3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。 4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。 MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1、RIPEMD以及Haval等。

SHA1 :安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准 (Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。 SHA1有如下特点: 1.不可以从消息摘要中复原信息; 2.两个不同的消息不会产生同样的消息摘要,(但会有1x10 ^ 48分之一的机率出现相同的消息摘要,一般使用时忽略)。

可逆加密:可逆加密有对称加密和非对称加密。

对称加密:【文件加密和解密使用相同的密钥,即加密密钥也可以用作解密密钥】

非对称加密:【两个密钥:公开密钥(publickey)和私有密钥,公有密钥加密,私有密钥解密】

常见问题

使用 cookie 时需要考虑的问题

使用 session 时需要考虑的问题

使用 token 时需要考虑的问题

使用 JWT 时需要考虑的问题

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

分布式架构下 session 共享方案

1. session 复制

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

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

2. 粘性 session /IP 绑定策略

优点: 简单,不需要对 session 做任何处理。

缺点: 缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的 session 信息都将失效。

适用场景: 发生故障对客户产生的影响较小;服务器发生故障是低概率事件 。

实现方式: 以 Nginx 为例,在 upstream 模块配置 ip_hash 属性即可实现粘性 session。

3. session 共享(常用)

4. session 持久化

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

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

只要关闭浏览器 ,session 真的就消失了?

不对。对 session 来说,除非程序通知服务器删除一个 session,否则服务器会一直保留,程序一般都是在用户做 log off 的时候发个指令去删除 session。

然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分 session 机制都使用会话 cookie 来保存 session id,而关闭浏览器后这个 session id 就消失了,再次连接服务器时也就无法找到原来的 session

如果服务器设置的 cookie 被保存在硬盘上,或者使用某种手段改写浏览器发出的 HTTP 请求头,把原来的 session id 发送给服务器,则再次打开浏览器仍然能够打开原来的 session。

恰恰是由于关闭浏览器不会导致 session 被删除,迫使服务器为 session 设置了一个失效时间,当距离客户端上一次使用 session 的时间超过这个失效时间时,服务器就认为客户端已经停止了活动,才会把 session 删除以节省存储空间。

项目地址

https://github.com/yjdjiayou/jwt-demo

巨人的肩膀:

https://juejin.im/post/6844904034181070861
https://www.jianshu.com/p/b2e23939ad46
https://blog.51cto.com/jamesfancy/2065665
https://blog.csdn.net/kaixuansui/article/details/94433920
https://www.cnblogs.com/yuki-nana/p/14001600.html
https://www.cnblogs.com/xiaozhang2014/p/7750200.html
https://mp.weixin.qq.com/s/j-6ngGKRJvB3gfY4VJaU4A

上一篇下一篇

猜你喜欢

热点阅读