专栏名称: 朱小厮的博客
著有畅销书:《深入理解Kafka》和《RabbitMQ实战指南》。公众号主要用来分享Java技术栈、Golang技术栈、消息中间件(如Kafka、RabbitMQ)、存储、大数据以及通用型技术架构等相关的技术。
目录
相关文章推荐
南京市场监管  ·  真相 | 护腰坐垫可以实现“久坐不累”? ·  17 小时前  
奔腾融媒 新闻天天看  ·  当心!这些常喝的饮品,正在悄悄升高你的尿酸 ·  昨天  
红古发布  ·  改善睡眠的方法来了:晚餐吃点它…… ·  昨天  
安徽交通广播  ·  “春捂”到底该“捂”哪儿?“捂”好这3处很关键 ·  2 天前  
都市频道  ·  连续久坐,一定别超过这个时间 ·  3 天前  
51好读  ›  专栏  ›  朱小厮的博客

一文读懂JWT,JWS,JWE

朱小厮的博客  · 公众号  ·  · 2019-11-02 17:31

正文

点击上方“ 朱小厮的博客 ”,选择“ 设为星标

后台回复” 1024 “领取惊喜资料


作者: zh_coder

来源: http://uee.me/c66kx


JWT(json web token)是设计一种简洁,安全,无状态的token的实现规范rfc7519,通常用于网络请求方和网络接收方之间的网络请求认证。

jwt的常用场景

1.1: restful api接口的无状态认证, 在传统的web应用中,我们通常采用session认证。session
认证的流程大概是这样的。

session认证流程 :

  • 客户端将用户名/密码通过某种加密的方式发送给服务器

  • 服务器接收到客户端请求之后进行验证,验证通过后使用Set-Cookie将用户的唯一sessionid放入到cookie当中,并将生成的sessionid和用户的关联信息存入到内存。

  • 客户端第二次访问后服务器从当前cookie中取出sessionid并从内存中拿到相同的sessionid. 如果不存在,或者没有携带sessionid则说明该用户登陆过期,或者未登陆。

session认证的一些缺点 :

  • 由于使用session进行认证的方式必须存储sessionid,当用户量过大时对服务器内存消耗影响巨大. 如果你没有设置session的过期时间(关闭浏览器并不会导致cookie消失)那么对你的服务器来说消耗是致命的。

  • 如果你没有将session存在一个所有服务器都可以获取得到的地方如redis, 那么意味着在本台服务器上面存储的sessionid其他服务器无法获取。用户进行请求时必须请求到这台服务器上面。可扩展性较差。

  • 跨平台性较差,传统的session认证方式在移动端很难行得通。你必须开发二套不同的逻辑对web和移动端进行认证。

jwt认证流程 :

  • 客户端将用户名/密码通过某种加密的方式发送给服务器。

  • 服务器接收到客户端请求后进行验证,验证通过服务器生成token返回给客户端。客户端将token存储在本地。

  • 客户端每次请求将token携带在http header头中, 服务器端将token取出进行解密。

jwt认证的优点 :

服务器端无需保存token,以加解密的方式代替存储,节省了内存空间。

无状态的token不依赖于服务器保存会话信息,更利于水平扩展。

相比于传统的session认证方式,jwt对移动端的支持更友好。

2.jwt的组成和生成方式

2.1jwt主要由三个部分组成,分别是头部(header),载荷(payload),签名(signature)组成。

header :

  • 头部是用来声明此jwt的类型和加密算法,它们通常由alg和typ这二个字段组成。rfc文档示范的header头

  • alg字段通常用于表示加密采用的算法。

  • typ字段通常用于表示类型。

{"typ":"JWT""alg":"HS256"//示范的jwt header头

payload :

  • 载荷就是我们存放公共参数/私有参数的地方.通俗点说该字段就是存放系统中用户的信息和jwt本身的一些信息,rfc文档本身替我们提供了一组字段的声明 (Claims)

  • iss: 该字段表示jwt的签发者。可以用你的应用唯一标识或者高权限的userid填充此字段。

  • sub: 该jwt面向的用户。

  • aud: jwt的接收方。

  • exp: jwt的过期时间,通常来说是一个时间戳。

  • iat: jwt的签发时间,常来说是一个时间戳。

  • jti:此jwt的唯一标识。通常用于解决请求中的重放攻击。该字段在大多数地方没有被提及或使用。因为使用此字段就意味着必须要在服务器维护一张jti表, 当客户端携带jwt访问的时候需要在jti表中查找这个唯一标识是否被使用过。使用这种方式防止重放攻击似乎让jwt有点怪怪的感觉, 毕竟jwt所宣称的优点就是无状态访问。-.-

//一个正儿八经的payload示范
{
    "iss""appid_xxxxxx"
    "sub""012345122",
    "exp""1572246721840",
    "iat""1592246721840"
}

signature签名流程 :

  • 首先将header和payload进行base64编码,然后使用"."将header和payload拼接起来。类似于像下面这样:

String base64data = Base64.encode(header)+"."+Base64.encode(payload)
  • 在将payload和header进行base64之后进行签名,得到签名后的数据。签名所使用的算法来自于header头中的alg字段。签名过程类似于像下面这样:

final JWSSigner signer = new ECDSASigner(this.privateKey);

this.signature = signer.sign(base64data);
//第一步, 实例化一个签名对象
//第二步,对base64data 进行签名
  • 签名之后将签名的值和base64之后的header和payload用"."号连接起来。此时一个完整的jwt就出来啦。

jwt的最终结构: header.payload.signature

3.使用jwe来使你的jwt更加安全

签名到底在干什么 :

在上面我们所谈到的jwt仅仅是签名后的jwt。在这里我们需要明白一个概念,那就是签名并不能保证数据的安全,也就是说如果有人获取到了你的jwt那么他可以通过转码得到你jwt当中所有的信息。那么读者可能会有点想骂人了,你特么上面说了那么多连一个数据安全都不能保证那么我看那么多有啥作用- -. 别急,我们先来了解一下签名的概念。其实对于签名更专业点的来说就是进行了一次哈希散列,对于散列我们首先要保证一下四点概念.

  • 相同的输入将始终产生相同的输出。

  • 多个不同的输入不应产生相同的输出。

  • 从输出到输入应该是不可能的。

  • 给定输入的任何修改都将导致哈希值发生巨大变化。

从上面4点大家看明白了吗?哈希与身份验证结合使用,可以产生强有力的证据来证明给定的消息尚未被修改。也就是说这个jwt从我这里签发以后无法改变,从而保证了数据来源的可靠性。当客户端携带jwt进行请求时服务器在执行一遍签名步骤。如果签名的值一样就表示这个jwt是可靠的。此时我们在客户端和服务器之间就建立一种可信任的token机制。

应该怎样保证数据安全 :

对于如何保证jwt本身的数据安全很多文章或文档都可以提及,我们可以把上面所生成的jwt成为jws(JSON Web Signed). 他本身的数据并没有进行加密。此时如果我们想保证数据的安全就需要使用jwe(JSON Web Encryption)对jwt进行加密。jwe加密的秘文如下所示

// jwe相对于jws来说多了二个组成部分。
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.
     OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe
     ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb
     Sv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaV
     mqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je8
     1860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi
     6UklfCpIMfIjf7iGdXKHzg.
     48V1_ALb6US04U3b.
     5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji
     SdiwkIr3ajwQzaBtQD_A.
     XFBoMYUZodetZdvTiFvSkQ

jwe的5个组成部分 :

  • JWE header: 描述用于创建jwe加密密钥和jwe密文的加密操作,类似于jws中的header。参数不一一描述,详情请见jwe header参数

  • JWE Encrypted Key:用来加密文本内容所采用的算法。

  • JWE initialization vector: 加密明文时使用的初始化向量值,有些加密方式需要额外的或者随机的数据。这个参数是可选的。

  • JWE Ciphertext:明文加密后产生的密文值。

  • JWE Authentication Tag:数字认证标签。

//一个完整的jwe json结构
{
    "protected":"jwe受保护的header头",
    "unprotected":"JWE Shared Unprotected Header数据",
    "header":"",
    "encrypted_key":"密钥加密后数据    ",
    "aad":"额外的认证数据",
    "iv":"同上的 JWE initialization vector",
    "ciphertext":"同上的JWE Ciphertext",
    "tag":"同上的JWE Authentication Tag"
}

jwe创建流程 :

  • 根据头部 alg 的声明,将header头进行编码

  • 随机生成密钥

  • 加密密钥

  • 生成iv如果不需要,此步骤可以省略.

  • 加密原始报文

  • 生成认证算法得到Authentication Tag.

  • 如果明文有声明zip压缩,那么压缩明文

Base64.encode(header)+"."+Base64.encode(encrypted_key)+","+Base64.encode(iv)+"."+Base64.encode






请到「今天看啥」查看全文


推荐文章
南京市场监管  ·  真相 | 护腰坐垫可以实现“久坐不累”?
17 小时前
奔腾融媒 新闻天天看  ·  当心!这些常喝的饮品,正在悄悄升高你的尿酸
昨天
都市频道  ·  连续久坐,一定别超过这个时间
3 天前
易观方舟AnalysysData  ·  中国智能硬件产业综述2017
7 年前
白无常C4D  ·  设计师书屋
7 年前
马哥Linux运维  ·  一张图掌握全部find命令用法
7 年前
上海房地产观察  ·  谁买谁倒霉:上海2017最滞销楼盘揭秘
7 年前