想起了 之前做过的 很多 登录授权 的项目 它相比原先的session、cookie来说,更快更安全,跨域也不再是问题,更关键的是更加优雅 ,所以今天总结了一篇文章来介绍他

JWT 指JSON Web Token,如果在项目中通过 jjwt 来支持 JWT 的话,可能只需要了解 JWT 一个概念即可,但是现在很多时候可能不是使用 jjwt,而是选择 nimbus-jose-jwt 库,此时就有可能接触到一些新的概念,如 JWE、JWS。那么 JWE、JWS 以及 JWT 之间是什么关系呢?

什么是 JWT

一个JWT,应该是如下形式的:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

这些东西看上很凌乱,但是非常紧凑,并且是可打印的主要用于验证签名的真实性。

JWT 解决什么问题?

JWT的主要目的是在服务端和客户端之间以安全的方式来转移声明。主要的应用场景如下所示:

  1. 认证 Authentication;
  2. 授权 Authorization // 注意这两个单词的区别;
  3. 联合识别;
  4. 客户端会话(无状态的会话);
  5. 客户端机密。

JWT 的一些名词解释

  1. JWS:Signed JWT签名过的jwt
  2. JWE:Encrypted JWT部分payload经过加密的jwt;目前加密payload的操作不是很普及;
  3. JWK:JWT的密钥,也就是常说的 scret;
  4. JWKset:JWT key set在非对称加密中,需要的是密钥对而非单独的密钥,在后文中会阐释;
  5. JWA:当前JWT所用到的密码学算法;
  6. nonsecure JWT:当头部的签名算法被设定为none的时候,该JWT是不安全的;因为签名的部分空缺,所有人都可以修改。

JWT的组成

一个通常看到的jwt,由以下三部分组成,它们分别是:

  1. header:主要声明了JWT的签名算法;
  2. payload:主要承载了各种声明并传递明文数据;
  3. signture:拥有该部分的JWT被称为JWS,也就是签了名的JWS;没有该部分的JWT被称为nonsecure JWT 也就是不安全的JWT,此时header中声明的签名算法为none。
    三个部分用·分割。形如 xxxxx.yyyyy.zzzzz的样式。

JWT header

{"typ": "JWT","alg": "none","jti": "4f1g23a12aa"
}

jwt header 的组成
头通常由两部分组成:令牌的类型,即JWT,以及正在使用的散列算法,例如HMAC SHA256或RSA。
当然,还有两个可选的部分,一个是jti,也就是JWT ID,代表了正在使用JWT的编号,这个编号在对应服务端应当唯一。当然,jti也可以放在payload中。
另一个是cty,也就是content type。这个比较少见,当payload为任意数据的时候,这个头无需设置,但是当内容也带有jwt的时候。也就是嵌套JWT的时候,这个值必须设定为jwt。这种情况比较少见。
jwt header 的加密算法
加密的方式如下:

base64UrlEncode(header)
>> eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIiwianRpIjoiNGYxZzIzYTEyYWEifQ

JWT payload

{"iss": "http://shaobaobaoer.cn","aud": "http://shaobaobaoer.cn/webtest/jwt_auth/","jti": "4f1g23a12aa","iat": 1534070547,"nbf": 1534070607,"exp": 1534074147,"uid": 1,"data": {"uname": "shaobao","uEmail": "shaobaobaoer@126.com","uID": "0xA0","uGroup": "guest"}
}

jwt payload的组成payload通常由三个部分组成,分别是 Registered Claims ; Public Claims ; Private Claims ;每个声明,都有各自的字段。
Registered Claims
● iss 【issuer】发布者的url地址
● sub 【subject】该JWT所面向的用户,用于处理特定应用,不是常用的字段
● aud 【audience】接受者的url地址
● exp 【expiration】 该jwt销毁的时间;unix时间戳
● nbf 【not before】 该jwt的使用时间不能早于该时间;unix时间戳
● iat 【issued at】 该jwt的发布时间;unix 时间戳
● jti 【JWT ID】 该jwt的唯一ID编号
Public Claims 这些可以由使用JWT的那些标准化组织根据需要定义,应当参考文档IANA JSON Web Token Registry。
Private Claims 这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公开声明。上面的payload中,没有public claims只有private claims。
jwt payload 的加密算法

加密的方式如下:

base64UrlEncode(payload)
>>eyJpc3MiOiJodHRwOi8vc2hhb2Jhb2Jhb2VyLmNuIiwiYXVkIjoiaHR0cDovL3NoYW9iYW9iYW9lci5jbi93ZWJ0ZXN0L2p3dF9hdXRoLyIsImp0aSI6IjRmMWcyM2ExMmFhIiwiaWF0IjoxNTM0MDcwNTQ3LCJuYmYiOjE1MzQwNzA2MDcsImV4cCI6MTUzNDA3NDE0NywidWlkIjoxLCJkYXRhIjp7InVuYW1lIjoic2hhb2JhbyIsInVFbWFpbCI6InNoYW9iYW9iYW9lckAxMjYuY29tIiwidUlEIjoiMHhBMCIsInVHcm91cCI6Imd1ZXN0In19

暴露的信息
所以,在JWT中,不应该在载荷里面加入任何敏感的数据。在上面的例子中,传输的是用户的User ID,邮箱等。这个值实际上不是什么敏感内容,一般情况下被知道也是安全的。但是像密码这样的内容就不能被放在JWT中了。如果将用户的密码放在了JWT中,那么怀有恶意的第三方通过Base64解码就能很快地知道密码信息了。
当然,这也是有解决方案的,那就是加密payload。在之后会说到。

什么是 JWS?

JWS ,也就是JWT Signature,其结构就是在之前nonsecure JWT的基础上,在头部声明签名算法,并在最后添加上签名。创建签名,是保证jwt不能被他人随意篡改。
为了完成签名,除了用到header信息和payload信息外,还需要算法的密钥,也就是secret。当利用非对称加密方法的时候,这里的secret为私钥。
为了方便后文的展开,把JWT的密钥或者密钥对,统一称为JSON Web Key,也就是JWK。
jwt signature 的签名算法

RSASSA || ECDSA || HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
>>GQPGEpixjPZSZ7CmqXB-KIGNzNl4Y86d3XOaRsfiXmQ
>># 上面这个是用 HMAC SHA256生成的

到目前为止,jwt的签名算法有三种。
● 对称加密HMAC【哈希消息验证码】:HS256/HS384/HS512
● 非对称加密RSASSA【RSA签名算法】(RS256/RS384/RS512)
● ECDSA【椭圆曲线数据签名算法】(ES256/ES384/ES512)
最后将签名与之前的两段内容用.连接,就可以得到经过签名的JWT,也就是JWS。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjRmMWcyM2ExMmFhIn0.eyJpc3MiOiJodHRwOi8vc2hhb2Jhb2Jhb2VyLmNuIiwiYXVkIjoiaHR0cDovL3NoYW9iYW9iYW9lci5jbi93ZWJ0ZXN0L2p3dF9hdXRoLyIsImp0aSI6IjRmMWcyM2ExMmFhIiwiaWF0IjoxNTM0MDcwNTQ3LCJuYmYiOjE1MzQwNzA2MDcsImV4cCI6MTUzNDA3NDE0NywidWlkIjoxLCJkYXRhIjp7InVuYW1lIjoic2hhb2JhbyIsInVFbWFpbCI6InNoYW9iYW9iYW9lckAxMjYuY29tIiwidUlEIjoiMHhBMCIsInVHcm91cCI6Imd1ZXN0In19.GQPGEpixjPZSZ7CmqXB-KIGNzNl4Y86d3XOaRsfiXmQ

当验证签名的时候,利用公钥或者密钥来解密Sign,和 base64UrlEncode(header) + “.” + base64UrlEncode(payload) 的内容完全一样的时候,表示验证通过。

JWS 的额外头部声明

如果对于CA有些概念的话,这些内容会比较好理解一些。为了确保服务器的密钥对可靠有效,同时也方便第三方CA机构来签署JWT而非本机服务器签署JWT,对于JWS的头部,可以有额外的声明,以下声明是可选的,具体取决于JWS的使用方式。如下所示:
● jku: 发送JWK的地址;最好用HTTPS来传输
● jwk: 就是之前说的JWK
● kid: jwk的ID编号
● x5u: 指向一组X509公共证书的URL
● x5c: X509证书链
● x5t:X509证书的SHA-1指纹
● x5t#S256: X509证书的SHA-256指纹
● typ: 在原本未加密的JWT的基础上增加了 JOSE 和 JOSE+ JSON。JOSE序列化后文会说及。适用于JOSE标头的对象与此JWT混合的情况。
● crit: 字符串数组,包含声明的名称,用作实现定义的扩展,必须由 this->JWT的解析器处理。不常见。

多重验证与JWS序列化

当需要多重签名或者JOSE表头的对象与JWS混合的时候,往往需要用到JWS的序列化。JWS的序列化结构如下所示:

{"payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
"signatures": [{"protected": "eyJhbGciOiJSUzI1NiJ9","header": { "kid": "2010-12-29" },"signature":"signature1"},{"protected": "eyJhbGciOiJSUzI1NiJ9","header": { "kid": "e9bc097a-ce51-4036-9562-d2ade882db0d" },"signature":"signature2"},...]
}

结构很容易理解。首先是payload字段,这个不用多讲,之后是signatures字段,这是一个数组,代表着多个签名。每个签名的结构如下:
● protected:之前的头部声明,利用b64uri加密;
● header:JWS的额外声明,这段内容不会放在签名之中,无需验证;
● signature:也就是对当前header+payload的签名。

什么是JWE

[JWE] 相关概念

JWE是一个很新的概念,总之,除了jwt的官方手册外,很少有网站或者博客会介绍这个东西。也并非所有的库都支持JWE。
JWS是去验证数据的,而JWE(JSON Web Encryption)是保护数据不被第三方的人看到的。通过JWE,JWT变得更加安全。
JWE和JWS的公钥私钥方案不相同,JWS中,私钥持有者加密令牌,公钥持有者验证令牌。而JWE中,私钥一方应该是唯一可以解密令牌的一方。
在JWE中,公钥持有可以将新的数据放入JWT中,但是JWS中,公钥持有者只能验证数据,不能引入新的数据。因此,对于公钥/私钥的方案而言,JWS和JWE是互补的。

JWE 的构成

一个JWE,应该是如下形式的:

eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.
UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_
i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKxYxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8Otv
zlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTPcFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.
AxY8DCtDaGlsbGljb3RoZQ.
KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.
9hH0vgRfYgPnAHOd8stkvw

JWE一共有五个部分,分别是:
● The protected header,类似于JWS的头部;
● The encrypted key,用于加密密文和其他加密数据的对称密钥;
● The initialization vector,初始IV值,有些加密方式需要额外的或者随机的数据;
● The encrypted data (cipher text),密文数据;
● The authentication tag,由算法产生的附加数据,来防止密文被篡改。

JWE 密钥加密算法

一般来说,JWE需要对密钥进行加密,这就意味着同一个JWT中至少有两种加密算法在起作用。但是并非将密钥拿来就能用,需要对密钥进行加密后,利用JWK密钥管理模式来导出这些密钥。JWK的管理模式有以下五种,分别是:
● Key Encryption
● Key Wrapping
● Direct Key Agreement
● Key Agreement with Key Wrapping
● Direct Encryption
并不是所有的JWA都能够支持这五种密钥管理管理模式,也并非每种密钥管理模式之间都可以相互转换。可以参考Spomky-Labs/jose中给出的表格(https://github.com/Spomky-Labs/jose/blob/master/doc/operation/Encrypt.md),至于各个密钥管理模式的细节,还请看JWT的官方手册,解释起来较为复杂。

JWE Header
就好像是JWS的头部一样。JWE的头部也有着自己规定的额外声明字段,如下所示:
● type:一般是 jwt
● alg:算法名称,和JWS相同,该算法用于加密稍后用于加密内容的实际密钥
● enc:算法名称,用上一步生成的密钥加密内容的算法。
● zip:加密前压缩数据的算法。该参数可选,如果不存在则不执行压缩,通常的值为 DEF,也就是deflate算法
● jku/jkw/kid/x5u/x5c/x5t/x5t#S256/typ/cty/crit:和JWS额额外声明一样。
JWE 的加密过程

步骤2和步骤3,更具不同的密钥管理模式,应该有不同的处理方式。在此只罗列一些通常情况。
之前谈及,JWE一共有五个部分。现在来详细说一下加密的过程:

  1. 根据头部alg的声明,生成一定大小的随机数;
  2. 根据密钥管理模式确定加密密钥;
  3. 根据密钥管理模式确定JWE加密密钥,得到CEK;
  4. 计算初始IV,如果不需要,跳过此步骤;
  5. 如果ZIP头申明了,则压缩明文;
  6. 使用CEK,IV和附加认证数据,通过enc头声明的算法来加密内容,结果为加密数据和认证标记;
  7. 压缩内容,返回token。
base64(header) + '.' +base64(encryptedKey) + '.' + // Steps 2 and 3base64(initializationVector) + '.' + // Step 4base64(ciphertext) + '.' + // Step 6base64(authenticationTag) // Step 6

多重验证与JWE序列化

和JWS类似,JWE也定义了紧凑的序列化格式,用来完成多种形式的加密。大致格式如下所示:

{"protected": "eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0","unprotected": { "jku":"https://server.example.com/keys.jwks" },"recipients":[{"header": { "alg":"RSA1_5","kid":"2011-04-29" },"encrypted_key":"UGhIOguC7Iu...cqXMR4gp_A"},{"header": { "alg":"A128KW","kid":"7" },"encrypted_key": "6KB707dM9YTIgH...9locizkDTHzBC2IlrT1oOQ"}],"iv": "AxY8DCtDaGlsbGljb3RoZQ","ciphertext": "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY","tag": "Mz-VPPyU4RlcuYv1IwIvzw"
}

结构很容易理解,如下所示:
● protected:之前的头部声明,利用b64uri加密;
● unprotected:一般放JWS的额外声明,这段内容不会被b64加密;
● iv:64加密后的iv参数;
● add:额外认证数据;
● ciphertext:b64加密后的加密数据;
● recipients:b64加密后的认证标志-加密链,这是一个数组,每个数组中包含了两个信息;
● header:主要是声明当前密钥的算法;
● encrypted_key:JWE加密密钥。

JWT 的工作原理

这里通过juice shop来说下jwt是如何工作的。在身份验证中,当用户使用其凭据成功登录时,将返回JSON Web令牌。
每当用户想要访问受保护的路由或资源时,用户将使用承载【bearer】模式发送JWT,通常在Authorization标头中。标题的内容应如下所示

Authorization: Bearer <token>

随后,服务器会取出token中的内容,来返回对应的内容。须知,这个token不一定会储存在cookie中,如果存在cookie中的话,需要设置为http-only,防止XSS。另外,还可以放在别的地方,比如localStorage、sessionStorage。如果使用vue的话,还可以存在vuex里面。
另外,如果在如Authorization: Bearer中发送令牌,则跨域资源共享(CORS)将不会成为问题,因为它不使用cookie。
此时,去访问认证页面,如预期所见,是利用Authorization:Bearer的请求头去访问的。

ECDSA|RSASSA or HMAC ?应该选用哪个?

首先必须明确一点,无论用的是 HMAC,RSASSA,ECDSA;密钥,公钥,私钥都不会发送给客户端,仅仅会保留在服务端上。
对称的算法HMAC适用于单点登录,一对一的场景中。速度很快。
但是面对一对多的情况,比如一个APP中的不同服务模块,需要JWT登录的时候,主服务端【APP】拥有一个私钥来完成签名即可,而用户带着JWT在访问不同服务模块【副服务端】的时候,副服务端只要用公钥来验证签名就可以了。从一定程度上也减少了主服务端的压力。
当然,还有一种情况就是不同成员进行开发的时候,大家可以用统一的私钥来完成签名,然后用各自的公钥去完成对JWT的认证,也是一种非常好的开发手段。
因此,构建一个没有多个小型“微服务应用程序”的应用程序,并且开发人员只有一组的,选择HMAC来签名即可。其他情况下,尽量选择RSA。

面试官: 你知道 JWT、JWE、JWS 、JWK嘛?相关推荐

  1. 面试官:谈谈JWT鉴权的应用场景及使用建议?

    作者:mantou叔叔 || 编辑:搜云库技术团队 出处:https://dwz.cn/7bikj3yk 1. JWT 介绍 JSON Web Token(JWT)是一个开放式标准(RFC 7519) ...

  2. JWT、JWE、JWS 、JWK 到底是什么?该用 JWT 还是 JWS?

    JWT 相信很多小伙伴都知道,JSON Web Token,如果在项目中通过 jjwt 来支持 JWT 的话,可能只需要了解 JWT 一个概念即可,但是现在很多时候我们可能不是使用 jjwt,而是选择 ...

  3. 一文理解 JWT、JWS、JWE、JWA、JWK、JOSE

    原文收录 GitBook--统一接口认证解决方案 JsonWebToken 关于JsonWebToken的专业名词解释: unsecured JWT:默认头部{"alg": &qu ...

  4. 面试官:要不讲讲 Cookie、Session、Token、JWT之间的区别?

    击上方"朱小厮的博客",选择"设为星标" 后台回复"加群",加入组织 来源:22j.co/btPm 什么是认证(Authentication ...

  5. jwt重放攻击_4个点搞懂JWT、JWS、JWE

    1.JWT是何物,有哪些常用的场景 JWT(json web token)是设计一种简洁,安全,无状态的token的实现规范rfc7519,通常用于网络请求方和网络接收方之间的网络请求认证. jwt的 ...

  6. 【262期】面试官:jwt 是什么?java-jwt 呢?懵逼了。。。

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方有惊喜,留言必回,有问必答! 每一天进步一点点,是成功的开始... JWT介绍 ...

  7. 3 JWT 和 JWS

    上一篇我们提到了token支持JWT格式,那这一篇来盘一下JWT到底是个啥. JSON Web Token(JWT) https://jwt.io JSON Web Token (JWT) (RFC ...

  8. 爆赞!Android岗大厂面试官常问的那些问题,论程序员成长的正确姿势

    开头 昨天去面了一家公司,价值观有受到冲击. 面试官技术方面没的说,他可能是个完美主义的人,无论什么事情到了他那里好像都有解决的方案,我被说的无所适从,感觉他很厉害. 但我不能认可的是,面试官觉得加班 ...

  9. qq空间登陆 cookie_看完这篇 Session、Cookie、Token,和面试官扯皮就没问题了||CSDN博文精选...

    作者:程序员cxuan Cookie 和 Session HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录:Session 和 ...

最新文章

  1. JavaScript - this详解 (三)
  2. 坦白局!一个大厂 Java 工程师近 20 年的进阶心得
  3. 一道并查集的(坑)题:关闭农场closing the farm
  4. 感知机数据算法的对偶形式
  5. 对require四种引入方式的认识
  6. jdk和cglib简单理解
  7. Python 中 异步协程 的 使用方法介绍
  8. 银辉机器人说明说_银辉儿童电动声控玩具 智能编程对话尊尼机器人 男孩礼物...
  9. 什么是产品的愿景—从一篇博文中学得到
  10. 使用ArcGIS软件对 .jpg 图片添加经纬网及地理配准失败的原因
  11. Matlab中矩阵的平方和矩阵中每个元素的平方介绍
  12. 用户设置代理如何获取真实IP
  13. avr单片机c语言计算log,AVR单片机定时器初值计算公式与方法 - 单片机定时器初值计算公式(51单片机和AVR单片机的初值计算三种方法)...
  14. VS2019项目自动包含bin或obj文件夹的问题
  15. html5画智利国旗,智利国旗与得州州旗,你能分的清么?
  16. 微软word如何插入页码_如何在Microsoft Word中插入,删除和管理超链接
  17. 目标检测使用的数据增强方法汇总
  18. 彻底删除微软拼音输入法这个讨厌的家伙
  19. 1040 有几个PAT (25分)
  20. C/C++语言100题练习计划 82——加勒比海盗船(贪心算法实现)

热门文章

  1. 缓存就是万金油,哪里有问题哪里抹一下 。那他的本质是什么呢?
  2. Windows 10设置菜单打不开
  3. Matlab似然函数
  4. iOS 获取所有国家名称
  5. Java程序设计(2021春)——第三章类的重用笔记与思考
  6. 渗透项目(五):W1R3S
  7. 记录:谷歌地图google map api实现基本测距功能
  8. Android 音频源码分析——AndroidRecord录音(一)
  9. 合法与不合法的标识符
  10. 弘辽科技:徒有贵族身份,却连一分钱都没有。