个人网站设计目的,青岛优化网站诊断,h5开发是做什么,制造动漫网站开发目的想起了 之前做过的 很多 登录授权 的项目 它相比原先的session、cookie来说#xff0c;更快更安全#xff0c;跨域也不再是问题#xff0c;更关键的是更加优雅 #xff0c;所以今天总结了一篇文章来介绍他 JWT 指JSON Web Token#xff0c;如果在项目中通过 jjwt 来支持 J… 想起了 之前做过的 很多 登录授权 的项目 它相比原先的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的主要目的是在服务端和客户端之间以安全的方式来转移声明。主要的应用场景如下所示
认证 Authentication授权 Authorization // 注意这两个单词的区别联合识别客户端会话无状态的会话客户端机密。
JWT 的一些名词解释
JWSSigned JWT签名过的jwtJWEEncrypted JWT部分payload经过加密的jwt目前加密payload的操作不是很普及JWKJWT的密钥也就是常说的 scretJWKsetJWT key set在非对称加密中需要的是密钥对而非单独的密钥在后文中会阐释JWA当前JWT所用到的密码学算法nonsecure JWT当头部的签名算法被设定为none的时候该JWT是不安全的因为签名的部分空缺所有人都可以修改。
JWT的组成
一个通常看到的jwt由以下三部分组成它们分别是
header主要声明了JWT的签名算法payload主要承载了各种声明并传递明文数据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)eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIiwianRpIjoiNGYxZzIzYTEyYWEifQJWT 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: shaobaobaoer126.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证书链 ● x5tX509证书的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加密 ● headerJWS的额外声明这段内容不会放在签名之中无需验证 ● signature也就是对当前headerpayload的签名。
什么是JWE
[JWE] 相关概念
JWE是一个很新的概念总之除了jwt的官方手册外很少有网站或者博客会介绍这个东西。也并非所有的库都支持JWE。 JWS是去验证数据的而JWEJSON Web Encryption是保护数据不被第三方的人看到的。通过JWEJWT变得更加安全。 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.
9hH0vgRfYgPnAHOd8stkvwJWE一共有五个部分分别是 ● 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一共有五个部分。现在来详细说一下加密的过程
根据头部alg的声明生成一定大小的随机数根据密钥管理模式确定加密密钥根据密钥管理模式确定JWE加密密钥得到CEK计算初始IV如果不需要跳过此步骤如果ZIP头申明了则压缩明文使用CEKIV和附加认证数据通过enc头声明的算法来加密内容结果为加密数据和认证标记压缩内容返回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加密 ● iv64加密后的iv参数 ● add额外认证数据 ● ciphertextb64加密后的加密数据 ● recipientsb64加密后的认证标志-加密链这是一个数组每个数组中包含了两个信息 ● header主要是声明当前密钥的算法 ● encrypted_keyJWE加密密钥。
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 应该选用哪个
首先必须明确一点无论用的是 HMACRSASSAECDSA密钥公钥私钥都不会发送给客户端仅仅会保留在服务端上。 对称的算法HMAC适用于单点登录一对一的场景中。速度很快。 但是面对一对多的情况比如一个APP中的不同服务模块需要JWT登录的时候主服务端【APP】拥有一个私钥来完成签名即可而用户带着JWT在访问不同服务模块【副服务端】的时候副服务端只要用公钥来验证签名就可以了。从一定程度上也减少了主服务端的压力。 当然还有一种情况就是不同成员进行开发的时候大家可以用统一的私钥来完成签名然后用各自的公钥去完成对JWT的认证也是一种非常好的开发手段。 因此构建一个没有多个小型“微服务应用程序”的应用程序并且开发人员只有一组的选择HMAC来签名即可。其他情况下尽量选择RSA。