关于JWT的理解

前言:

什么是JWT:

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519),
该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。
JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

本篇只介绍了理论知识相关,对应.Net Core的使用见:
https://github.com/Ybbbb/JsonWebToken

JWT的组成

头部 header

头部承载两部分信息:声明类型和声明加密的算法 ,
完整的头部就像下面这样的JSON:

  header:  {
      'typ': 'JWT',  // 类型
      'alg': 'HS256' // 使用的加密算法 通常直接使用 HMAC SHA256
    }

将头部进行base64UrlEncode加密(该加密是可以对称解密的),构成了第一部分

载荷 payload

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,
注意:不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
这些有效信息包含三个部分:
1、标准声明:

  • iss(issuer):jwt签发者
  • sub(subject):jwt所面向的用户
  • aud(audience):接收jwt的一方
  • exp(expiration):jwt的过期时间
  • nbf(notBefore):jwt的使用时间不能早于该时间
  • iat(issuedAt): jwt的签发时间
  • jti (jwtId):jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

2、公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息

3、私有的声明:
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

将playload进行base64UrlEncode加密,得到Jwt的第二部分:

payload:
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
签名哈希 signature

签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。

首先,需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用标头中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名。

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

在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。

JWT生成编码后的样子:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.  // 头部 
eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8y. // 载荷 这里为了方便展示缩略了,其实载荷很长
At4MhxKfSZ7JrMGxGtrLXyE6LMxLi1dChftstRU-1LY // 签名

JWT验证的过程

详细过程可参考:https://www.jianshu.com/p/6bfeb86885a3

1、首先客户端发出请求,并在请求头里面附带上Token。
2、服务端在接受到请求后拿到Token后,通过逗号分隔开头部、载荷和签名。并进行解码,拿到头部里声明的签名算法。
3、对头部和载荷用同一算法再次以同样的方法签名,并与请求中拿到的签名进行对比,如果对比之后发现,自己计算出来的签名和接收到的签名不一样,那么就说明这个Token的内容被别人动过的,我们应该拒绝这次请求,并返回一个错误码。
在这里插入图片描述

应用图示:

在这里插入图片描述
一般是在请求头里加入Authorization,并加上Bearer标注:

fetch('api/user/1', {
  headers: {
    'Authorization': 'Bearer ' + token
  }
})

服务端会验证token,如果验证通过就会返回相应的资源。

对JWT的总结

优点:

  • 在payload 载荷中可以包含足够多的信息比如用户名等,以便在后续请求中减少查询数据库的机率。
  • 因为token本身是无状态的,所以可以用一套认证代码来进行pc端、移动端等多端的授权。
  • 因为token更多的是通过header进行传递,所以不存在跨域问题。
  • JWT使用已经标准化了,资料也很多,学习成本不高
  • 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,NodeJS,PHP等很多语言都可以使用。

缺点:
JWT的最大缺点是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦JWT签发,在有效期内将会一直有效。

使用JWT要注意的地方:

  • 不应该在JWT的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
  • 为了减少盗用和窃取,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。

对比传统的session认证:
http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行, 因为我们并不能知道是哪个用户发出的请求。
所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。
但是这种基于session的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户,而这时候基于session认证应用的问题就会暴露出来。

基于session认证所显露的问题:

开销大: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。

扩展性弱: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

CSRF:因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章