Author:NinthDevilHunster\Source:https://www.freebuf.com/artic...JWTIbelievemanyfriendsknowthatJSONWebToken,ifyouusejjwttosupportJWTinyourproject,youmayonlyneedtoknowJWTisaconcept,butnowwemaynotusejjwt,butchoosenimbus-jose-jwtlibrary.Atthistime,wemaycomeintocontactwithsomenewconcepts,suchasJWEandJWS.SowhatistherelationshipbetweenJWE,JWSandJWT?RecentlyIsawagoodarticletalkingaboutthis,let'stakealooktogether,thefollowingisthetext.JWT什么是JWT一个JWT,应该是如下形式的:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ这些东西看上很凌乱,但是非常紧凑,并且是可打印的主要用于验证签名的真实性。WhatproblemdoesJWTsolve?ThemainpurposeofJWTistotransferclaimsbetweenserverandclientinasecuremanner.Themainapplicationscenariosareasfollows:authenticationAuthentication;AuthorizationAuthorization//Payattentiontothedifferencebetweenthesetwowords;jointidentification;clientsession(statelesssession);clientconfidentiality.SometermsofJWTexplainJWS:SignedJWTsignedjwtJWE:EncryptedJWTpartofthepayloadencryptedjwt;currentlytheoperationofencryptingpayloadisnotverypopular;JWK:JWTkey,whichiswhatweoftencallsecret;JWKset:JWTInasymmetricencryption,keysetrequiresakeypairratherthanaseparatekey,whichwillbeexplainedlater;JWA:thecryptographicalgorithmusedbythecurrentJWT;nonsecureJWT:whenthesignaturealgorithmoftheheaderissetWhenitisnone,theJWTisinsecure;becausethesignaturepartisblank,everyonecanmodifyit.JWT的组成大家通常看到的一个jwt由以下三部分组成,分别是:header:主要声明了JWT的签名算法;payload:主要携带各种声明,传输明文数据;signature:拥有这部分的JWT称为JWS,即signedJWS;没有这部分的JWT称为nonsecureJWT,即不安全的JWT。此时header中声明的签名算法为none。这三部分以·划分。像xxxxx.yyyyy.zzzzz这样的样式。JWTheader{"typ":"JWT","alg":"none","jti":"4f1g23a12aa"}jwtheader的组成header通常由两部分组成:token的类型,也就是JWT,以及使用的令牌类型哈希算法,例如HMACSHA256或RSA。当然还有两个可选的部分,一个是jti,也就是JWTID,代表正在使用的JWT的编号,这个编号在对应的服务器上应该是唯一的。当然jti也可以放在payload里面。另一个是cty,也就是内容类型。这是比较少见的。当payload是任意数据时,这个header不需要设置,但是当content中也包含jwt时。即在嵌套JWT时,这个值必须设置为jwt。这种情况比较少见。jwtheader加密算法如下:base64UrlEncode(header)>>eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIiwianRpIjoiNGYxZzIzYTEyYWEifQJWTpayload{"iss":"http://shaobaobaoer.cn","aud":"http://shaobaobaoerwt.cn/webtest/j","jti":"4f1g23a12aa","iat":1534070547,"nbf":1534070607,"exp":1534074147,"uid":1,"data":{"uname":"shaobao","uEmail"":"shaobaobaoer@126.com","uID":"0xA0","uGroup":"guest"}}jwtpayload的组成payload通常由三部分组成,分别是RegisteredClaims;公共索赔;私人索赔;每个语句都有自己的字段。RegisteredClaimsis[issuer]issuersub[subject]JWT所针对的用户的url地址,用于处理具体的应用,不是常用的字段aud[audience]接收者的url地址exp[expiration]时间当jwt被销毁时;unixtimestampnbf[notbefore]jwt的使用时间不能早于这个时间;unixtimestampiat[issuedat]jwt的发布时间;unixtimestampjti[JWTID]jwtPublicClaims的唯一标识号这些那些使用JWT的标准化组织可以根据需要定义,需要参考文档IANAJSONWebTokenRegistry。私人声明这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公共声明。在上面的有效负载中,没有公共声明,只有私有声明。jwtpayload的加密算法加密的方式如下:base64UrlEncode(payload)>>eyJpc3MiOiJodHRwOi8vc2hhb2Jhb2Jhb2VyLmNuIiwiYXVkIjoiaHR0cDovL3NoYW9iYW9iYW9lci5jbi93ZWJ0ZXN0L2p3dF9hdXRoLyIsImp0aSI6IjRmMWcyM2ExMmFhIiwiaWF0IjoxNTM0MDcwNTQ3LCJuYmYiOjE1MzQwNzA2MDcsImV4cCI6MTUzNDA3NDE0NywidWlkIjoxLCJkYXRhIjp7InVuYW1lIjoic2hhb2JhbyIsInVFbWFpbCI6InNoYW9iYW9iYW9lckAxMjYuY29tIiwidUlEIjoiMHhBMCIsInVHcm91cCI6Imd1ZXN0In19暴露的信息所以,在JWT中,不应该在载荷里面加入任何敏感的数据。Intheaboveexample,wearetransmittingtheuser'sUserID,emailaddress,etc.Thisvalueisactuallynotsensitive,anditisgenerallysafetobeknown.ButcontentsuchaspasswordscannotbeplacedinJWT.Ifyouputtheuser'spasswordinJWT,thenamaliciousthirdpartycanquicklyknowyourpasswordthroughBase64decoding.Ofcourse,thereisasolutiontothis,andthatistoencryptthepayload.IwilltalkabouttheconceptofJWSJWSlater.JWS,thatis,JWTSignature,itsstructureisbasedonthepreviousnonsecureJWT,thesignaturealgorithmisdeclaredintheheader,andthesignatureisaddedattheend.Creatingasignatureistoensurethatjwtcannotbetamperedwithbyothers.Inordertocompletethesignature,inadditiontotheheaderinformationandpayloadinformation,thekeyofthealgorithmisalsorequired,thatis,thesecret.Whenusinganasymmetricencryptionmethod,thesecrethereisaprivatekey.Inordertofacilitatethedevelopmentofthefollowingtext,wecollectivelyrefertotheJWTkeyorkeypairasJSONWebKey,orJWK.jwt签名RSASSA的签名算法||ECDSA||HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)>>GQPGEpixjPZSZ7CmqXB-KIGNzNl4Y86d3XOaRsfiXmQ>>#以上是目前为止用HMACSHA256生成的,jwt签名算法一共有三种。对称加密HMAC【哈希消息认证码】:HS256/HS384/HS512非对称加密RSASSA【RSA签名算法】(RS256/RS384/RS512)ECDSA【椭圆曲线数据签名算法】(ES256/ES384/ES512)最后签名Connect与前两段同。得到一个签名的JWT,也就是JWS。eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjRmMWcyM2ExMmFhIn0.eyJpc3MiOiJodHRwOi8vc2hhb2Jhb2Jhb2VyLmNuIiwiYXVkIjoiaHR0cDovL3NoYW9iYW9iYW9lci5jbi93ZWJ0ZXN0L2p3dF9hdXRoLyIsImp0aSI6IjRmMWcyM2ExMmFhIiwiaWF0IjoxNTM0MDcwNTQ3LCJuYmYiOjE1MzQwNzA2MDcsImV4cCI6MTUzNDA3NDE0NywidWlkIjoxLCJkYXRhIjp7InVuYW1lIjoic2hhb2JhbyIsInVFbWFpbCI6InNoYW9iYW9iYW9lckAxMjYuY29tIiwidUlEIjoiMHhBMCIsInVHcm91cCI6Imd1ZXN0In19.GQPGEpixjPZSZ7CmqXB-KIGNzNl4Y86d3XOaRsfiXmQ当验证签名的时候,利用公钥或者密钥来解密Sign,和base64UrlEncode(header)+"."+base64UrlEncode(payload)的内容完全一样的时候,表示验证通过。如果你对JWS的extraheader声明中的CA有一些概念,这些内容会更容易理解。为了保证服务器的密钥对可靠有效,也方便第三方CA机构对JWT进行签名,而不是本地服务器对JWT进行签名,可以对JWS头进行额外的声明。以下声明是可选的,具体取决于如何使用JWS。如下:jku:发送JWK的地址;最好用HTTPS传输jwk:就是前面说的JWK。kid:jwk的ID号x5u:指向一组X509公共证书的URL1Fingerprintx5t#S256:X509证书的SHA-256指纹typ:JOSE和JOSE+JSON是在原来未加密的JWT的基础上增加的。JOSE序列化后面会提到。适用于JOSE标头的对象与此J??WT混合的情况。crit:包含声明名称的字符串数组,用作实现定义的扩展,必须由this->JWT的解析器处理。异常。多重身份验证和JWS序列化当多重签名或JOSE标头对象与JWS混合时,通常需要JWS序列化。JWS的序列化结构如下所示:{"payload":"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ","signatures":[{"protected":"eyJhbGciOiJSUzI1NiJ9","header":{"kid":"2010-12-29"},“签名”:“签名1”},{“受保护”:“eyJhbGciOiJSUzI1NiJ9”,“标题”:{“孩子”:“e9bc097a-ce51-4036-9562-d2ade882db0d”},“签名”:“签名2”},..]}结构很容易理解。首先是payload字段,不用多说,接下来是signatures字段,是一个代表多个签名的数组。每个签名的结构如下:protected:前面的header声明,用b64uri加密;header:JWS的附加声明,此内容不会放在签名中,不需要校验;signature:即当前header+payload的标志。JWEJWE相关概念JWE是一个很新的概念。总之,除了jwt的官方手册,很少有网站或者博客会介绍这个东西。也不是所有的库都支持JWE。这里记录下我看了官方手册后的理解。JWS是为了验证数据,JWE(JSONWebEncryption)是为了保护数据不被第三方看到。有了JWE,JWT变得更加安全。JWE和JWS的公钥和私钥方案不同。在JWS中,私钥持有者加密令牌,公钥持有者验证令牌。在JWE中,私钥方应该是唯一可以解密token的一方。在JWE中,公钥持有者可以向JWT中放入新数据,而在JWS中,公钥持有者只能验证数据,不能引入新数据。因此,对于公钥/私钥方案,JWS和JWE是互补的。JWE的构成一个JWE,应该是如下形式的:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKxYxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTPcFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.9hH0vgRfYgPnAHOd8stkvw如你所见JWE一共有五个部分,分别是:Theprotectedheader,similartotheheaderofJWS;Theencryptedkey,thesymmetrickeyusedtoencryptciphertextandotherencrypteddata;Theinitializationvector,theinitialIVvalue,someencryptionmethodsrequireadditionalorrandomdata;Theencrypteddata(ciphertext),ciphertextdata;Theauthenticationtag,additionaldatageneratedbythealgorithmtopreventciphertextfrombeingtamperedwith.JWEkeyencryptionalgorithmGenerallyspeaking,JWEneedstoencryptthekey,whichmeansthatatleasttwoencryptionalgorithmsareworkinginthesameJWT.Butitisnotpossibletousethekeys.WeneedtoencryptthekeysandusetheJWKkeymanagementmodetoderivethesekeys.JWK有五种管理模式,分别是:KeyEncryptionKeyWrappingDirectKeyAgreementKeyAgreementwithKeyWrappingDirectEncryption并不是所有的JWA都能支持这五种密钥管理模式,也不是所有的密钥管理模式都相互兼容。可以相互转化。可以参考Spomky-Labs/jose中给出的表格:https://github.com/Spomky-Lab...关于每种密钥管理方式的详细介绍,请参考JWT官方手册,比较详细解释起来很复杂。JWEHeader就像是JWS的头部。JWE的header也有自己额外声明的字段,如下:type:一般是jwtalg:算法名,和JWS一样,这个算法是用来加密后面加密内容的实际密钥用的enc:算法名,算法使用上一步生成的密钥加密内容。zip:加密前压缩数据的算法。此参数是可选的。如果不存在,则不执行压缩。通常的值是DEF,也就是deflate算法jku/jkw/kid/x5u/x5c/x5t/x5t#S256/typ/cty/crit:和JWSamountofadditionaldeclarations一样。JWE的加密过程中的第2步和第3步的密钥管理方式不同,应该区别对待。这里只列出一些常见的情况。如前所述,JWE有五个部分。下面详细说一下加密过程:根据headeralg语句,生成一个一定大小的随机数;根据密钥管理方式确定加密密钥;根据密钥管理方式确定JWE加密密钥,得到CEK;计算初始IV,如果不需要,跳过这一步;如果ZIP标头声明,则压缩明文;使用CEK、IV和附加认证数据,通过enc头中声明的算法对内容进行加密,结果为加密数据和认证标志;压缩内容,返回令牌。base64(header)+'.'+base64(encryptedKey)+'.'+//步骤2和3base64(initializationVector)+'.'+//步骤4base64(密文)+'.'+//Step6base64(authenticationTag)//Step6Multi-factorauthentication类似于JWE序列化和JWS。JWE还为多种形式的加密定义了一种紧凑的序列化格式。大概的格式如下:":{"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:前面的header语句,用b64uri加密;unprotected:一般放JWS的额外声明,这个内容不会被b64加密;iv:64位加密后的iv参数;添加:额外的身份验证数据;密文:b64加密后的加密数据;recipients:b64加密后的认证标志-加密链,是一个数组,每个数组包含两条信息;header:主要声明当前key的算法;encrypted_key:JWE加密密钥。JWT的工作原理下面介绍一下jwt是如何通过juiceshop进行工作的。在身份验证中,当用户使用其凭据成功登录时,将返回一个JSONWebToken。如下图:此时返回了jwttoken。每当用户想要访问受保护的路由或资源时,用户将使用承载方式发送JWT,通常在Authorization标头中。title的内容应该是这样的:Authorization:Bearer
