浅谈JWT(Json Web Token)

一、什么是JWT(Json Web Token)?

JWT,在HTTP通信过程中,进行身份认证。它是一种开放标准,一种规范化之后的 JSON 结构的 Token。JWT 自身包含了身份验证所需要的所有信息,因此我们的服务器不需要存储 Session 信息。增加了系统的可用性和伸缩性,大大减轻了服务端的压力。

对比Session和JWT实现认证授权

首先我们要知道什么是授权。授权就是获得一定的权限后,才能进行某些操作。

假设我们现在在逛某宝,然后想要查看自己的购物车,那么这时候服务器肯定会对我们进行判断,只有我们登录了才能查看自己的购物车。这个登录的过程就可以理解为对我们进行授权的过程。

先看看如何通过Session进行授权的:

  • 客户端通过用户名和密码进行登录
  • 服务器验证身份后,生成一个Sessionid存在Cookie中,将对应的Session保存在内存
  • 客户端访问购物车(携带Sessionid)
  • 服务器从Cookie中取出Sessionid,查找对应的Session
  • 如果能够找到对应的Session,则该用户已登录,可以访问购物车,反之不行

再看看JWT是如何进行授权的:

  • 客户端通过用户名和密码进行登录
  • 服务器验证身份后,生成一个Token保存在Cookie中返回给客户端
  • 客户端访问购物车(客户端每次请求都会携带Token
  • 服务器取出Token进行验证
  • 如果验证成功,则该用户已登录,可以访问购物车

对比之下我们可以发现,JWT是不用在服务器保存用户的登录信息(Session)的,只用对Token进行验证, 验证成功后返回客户端希望得到的数据就可以了。

二、JWT组成部分

JWT是一个很长的字符串,中间用点(.)分隔成三个部分,分别是Header(头部)、Payload(负载)、Signature(签名)。JWT内部是没有换行的,并且都使用Base64编码。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0p21K0ab-1661850662370)(E:/Blog/lansg/source/img/image-20220830151500002.png)]

1.Header

Header部分是一个JSON对象,描述JWT最基本的信息,例如Token类型及签名所用的算法等。表示如下:

{
	"alg": "HS256",
	"typ": "JWT"
}

alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);

typ属性表示这个令牌(token)的类型(type),JWT令牌统一写为JWT。

最后,将上面的JSON对象使用Base64URL算法转成字符串。

2.Payload

Payload部分也是一个JSON对象也是使用Base64URL算法转成的字符串,用来存放实际需要传递的数据。JWT规定了7个官方字段,供选用。

  • iss (issuer):该JWT的签发者

  • exp (expiration time):过期时间(为一个UNIX时间戳)

  • sub (subject):该JWT所面向的用户

  • aud (audience):接受该JWT的一方

  • nbf (Not Before):生效时间

  • iat (Issued At) :签发时间

  • jti (JWT ID):编号

{
    "iss": "John Wu JWT",
    "iat": 1441593502,
    "exp": 1441594722,
    "aud": "www.example.com",
    "sub": "jrocket@example.com",
    "from_user": "B",
    "target_user": "A"
}

Payload 部分默认是不加密的,一定不要将隐私信息存放在 Payload 当中!

3.Signature

Signature 部分是对前两部分的签名,作用是防止 JWT(主要是 payload) 被篡改。

这个签名的生成需要用到:

  • Header + Payload
  • secret:存放在服务端的密钥
  • 签名算法

签名计算公式如下:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,这个字符串就是 JWT 。

JWT是如何进行校验的

服务端拿到 JWT 之后,会解析出其中包含的 Header、Payload 以及 Signature 。服务端会根据 Header、Payload、密钥再次生成一个 Signature。拿新生成的 Signature 和 JWT 中的 Signature 作对比,如果一样就说明 Header 和 Payload 没有被修改。

所以密钥是很重要的,密钥决定了签名签名决定了JWT的安全性

三、JWT的特点

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

(2)JWT不加密的情况下,不能将重要数据写入JWT。

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

(4)JWT的最大缺点是,由于服务器不保存session状态,因此无法在使用过程中废止某个token,或者更改token的权限。也就是说,一旦JWT签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

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

(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用HTTPS协议传输。

(7)便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的

(8)它不需要在服务端保存会话信息,所以它易于应用的扩展

四、JWT应用

  • 实现单点登录
  • 解决CSRF问题

1.单点登录

在有多个系统的情况下,我们在A系统登录了,如何让B系统也感知到我们已经登录?

通过JWT的Token,用户访问不同的系统时,只需要从Cookie中取出Token,将Token进行验证一下就可以了。

不过这样还有一个问题,Cookie是不能跨域的

比如说,我们请求<https://www.google.com/>时,浏览器会自动把google.com的Cookie带过去给google的服务器,而不会把<https://www.baidu.com/>的Cookie带过去给google的服务器。

这就意味着,由于域名不同,用户向系统A登录后,系统A返回给浏览器的Cookie,用户再请求系统B的时候不会将系统A的Cookie带过去。

关于跨域问题

跨域的根本原因就是因为浏览器的同源策略,这是浏览器出于安全性考虑做出的限制,所谓同源是指:域名协议端口相同。

比如在互联网上有两个资源(网页或者请求等),如果A想要访问B的资源,如果A、B并非同源,即域名、协议、端口有任意一个不相同,那么就会出现跨域问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CmrGZNcE-1661850662371)(E:/Blog/lansg/source/img/image-20220830162300092.png)]

为了解决Cookie的跨域问题,我们可以采取以下几种方法:

  • 服务端将Cookie写到客户端后,客户端对Cookie进行解析,将Token解析出来,请求时将Token放到Http报文的Header部分
  • 多个域名共享Cookie,在写到客户端的时候设置Cookie的domain
  • 将Token保存在SessionStroage中(不依赖Cookie就没有跨域的问题了)

例如:www.taobao.com、nv.taobao.com、nz.taobao.com、login.taobao.com

Set-Cookie: jwt=lll.zzz.xxx; HttpOnly; max-age=980000; domain=.taobao.com

注意domain必须设置为一个点加顶级域名,即.taobao.com。这样,taobao.com和*.taobao.com就都可以接受到这个Cookie,并获取JWT了。

2.解决CSRF问题

CSRF,也叫跨站请求伪造,攻击者通过盗用你的身份,以你的名义发送恶意请求。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rft7xg9V-1661850662372)(E:/Blog/lansg/source/img/image-20220830163558670.png)]

JWT是如何防止CSRF呢?

CSRF是依靠盗用用户的Cookie来得到用户身份,实现发送请求。为了防止Cookie被盗用,我们可以将JWT的Token存放在SessionStorage或者LocalStorage中,发送请求时将Token放在请求头中。这样不依赖Cookie,自然也就无法进行CSRF攻击了。

web本地存储SessionStorage和LocalStorage

  • sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。
  • localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。

版权声明:本文为lans_g原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。