1. 
          

          1. 新聞動(dòng)態(tài)

            你可能沒(méi)那么了解 JWT

            常見(jiàn)問(wèn)題 發(fā)布者:ou3377 2021-12-08 09:04 訪(fǎng)問(wèn)量:162

            圖片

            0)前言

            最近在開(kāi)發(fā)一個(gè)統一認證服務(wù),涉及到 OIDC 協(xié)議,其中授權碼模式所頒發(fā)的 id_token 使用的是 JWT ( JSON Web Token ) ,因為這次使用的庫的默認簽名算法和以往不同,所以特地去翻閱了 JWT 的 RFC 文檔( RFC 7519[1] ),一番閱讀后發(fā)現原來(lái)對 JWT 的認知只停留在表面,還有更多深層的內容是不知道的。

            1)我們最常使用的 JWT

            每次提到無(wú)狀態(tài)的 JWT 時(shí)相信都會(huì )看到另一種基于 Session 的用戶(hù)認證方案介紹,這里也不例外,Session 的認證流程通常會(huì )像這樣:

            圖片

            這種方案有一些缺點(diǎn):

            • 需要從內存或數據庫里存取 session 數據
            • 擴展性差,對于分布式應用,需要實(shí)現 session 數據共享

            JWT 正好可以解決這些問(wèn)題:

            圖片

            JWT 的魔法很簡(jiǎn)單,將需要使用到的用戶(hù)數據等信息放入 JWT 里面,每次請求都會(huì )攜帶上,只要保證密鑰不泄露,JWT 就無(wú)法偽造。

            一個(gè)簡(jiǎn)單的 JWT 示例如下:

            eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIyMDIxLTEwLTI0IDAwOjAwOjAwIiwibmFtZSI6InRvZ2V0dG95b3UifQ.XdF46NflSUjnt-adAc6rNZEXI1OD6nxtwGuhz9qkxUA

            jwt.io[2] 這個(gè)網(wǎng)站相信沒(méi)有人不知道了,把上面的 JWT 復制粘貼到網(wǎng)站中

            圖片

            可以看出 JWT 以不同顏色區分,兩個(gè)小數點(diǎn)隔開(kāi),分為了三部分

            ① Header(頭部):JSON 對象,描述 JWT 的元數據。其中 alg 屬性表示簽名的算法(algorithm),默認是 HMAC SHA256(寫(xiě)成 HS256);typ 屬性表示這個(gè)令牌(token)的類(lèi)型(type),統一寫(xiě)為 JWT

            ② Payload(載荷):JSON 對象,存放實(shí)際需要傳遞的數據,支持自定義字段

            ③ Signature(簽名):這部分就是 JWT 防篡改的精髓,其值是對前兩部分 base64UrlEncode 后使用指定算法簽名生成,以默認 HS256 為例,指定一個(gè)密鑰(secret),就會(huì )按照如下公式生成:

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

            到這里,大多數人對 JWT 的認知應該是停留在此了,日常使用也已經(jīng)足夠,但你想更深入了解 JWT 的話(huà),那你就得知道 JOSE 。

            2)JOSE 規范

            什么是 JOSE ,它和 JWT 之間又有什么關(guān)系呢。

            JOSE 全稱(chēng) JSON Object Signing and Encryption ( RFC 7165[3] , RFC 7520[4] ),它定義了一系列的標準,用來(lái)規范網(wǎng)絡(luò )傳輸過(guò)程中使用 JSON 的方式,我們上面一直說(shuō)的 JWT 其實(shí)是 JOSE 體系之一。

            圖片

            其中 JWT 又可分為 JWS 和 JWE 兩種不同的實(shí)現,我們大部分日常所使用的,所說(shuō)的 JWT 其實(shí)應該屬于 JWS 。 為什么這么說(shuō),請看下文。

            3)JWA 和 JWS 以及 JWK

            JWA 的全稱(chēng)是 JSON Web Algorithms ( RFC 7518[5] ) ,字如其名, JOSE 體系中涉及到的所有算法就是它來(lái)定義的,比如通用算法有 Base64-URL 和 SHA,簽名算法有 HMAC,RSA 和 Elliptic Curve(EC 橢圓曲線(xiàn)),本文不會(huì )深入到算法原理(我也不懂),只是想讓你知道 JWA 是做什么的。我們上面的 JWT 例子中第一部分 Header 有個(gè) alg 屬性,其值是 HS256 ,也就是 HMAC + SHA256 算法。

            說(shuō)了那么多,好像都沒(méi)有正式介紹過(guò) JWS 。JWS 的全稱(chēng)是 JSON Web Signature ( RFC 7515[6] ) ,它的核心就是簽名,保證數據未被篡改,而檢查簽名的過(guò)程就叫做驗證。更通俗的理解,就是對應前面提到的 JWT 的第三部分 Signature ,所以我才會(huì )說(shuō)我們日常所使用的 JWT 都是 JWS 。

            通常在客戶(hù)端-服務(wù)端模式中,JWS 使用 JWA 提供的 HS256 算法加上一個(gè)密鑰即可,這種方式嚴格依賴(lài)密鑰,但在分布式場(chǎng)景,可能多個(gè)服務(wù)都需要驗證 JWT ,若要在每個(gè)服務(wù)里面都保存密鑰,那么安全性將會(huì )大打折扣,要知道,密鑰一旦泄露,任何人都可以隨意偽造 JWT 。

            解決辦法就是使用非對稱(chēng)加密算法 RSA ,RSA 有兩把鑰匙,一把公鑰,一把私鑰,可以使用私鑰簽發(fā)(簽名分發(fā)) JWT ,使用公鑰驗證 JWT ,公鑰是所有人都可以獲取到的。這樣一來(lái),就只有認證服務(wù)保存著(zhù)私鑰,進(jìn)行簽發(fā),其他服務(wù)只能驗證。

            如下是一個(gè)使用 RS256 ( RSA + SHA256 ) 算法生成的 JWT :

            eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjF6aXlIVG15M184MDRDOU1jUENHVERmYWJCNThBNENlZG9Wa3VweXdVeU0ifQ.eyJqdGkiOiIzWUJ5eWZ2TDB4b01QNXdwTXVsZ0wiLCJzdWIiOiI2MDE5NDI5NjgwMWRjN2JjMmExYjI3MzUiLCJpYXQiOjE2MTI0NDQ4NzEsImV4cCI6MTYxMzY1NDQ3MSwic2NvcGUiOiJvcGVuaWQgZW1haWwgbWVzc2FnZSIsImlzcyI6Imh0dHBzOi8vc3RlYW0tdGFsay5hdXRoaW5nLmNuL29pZGMiLCJhdWQiOiI2MDE5M2M2MTBmOTExN2U3Y2IwNDkxNTkifQ.cYyZ6buwAjp7DzrYQEhvz5rvUBhkv_s8xzuv2JHgzYx0jbqqsWrA_-gufLTFGmNkZkZwPnF6ktjvPHFT-1iJfWGRruOOMV9QKPhk0S5L2eedtbKJU6XIEkl3F9KbOFwYM53v3E7_VC8RBj5IKqEY0qd4mW36C9VbS695wZlvMYnmXhIopYsd5c83i39fLBF8vEBZE1Rq6tqTQTbHAasR2eUz1LnOqxNp2NNkV2dzlcNIksSDbEGjTNkWceeTWBRtFMi_o9EWaHExdm5574jQ-ei5zE4L7x-zfp9iAe8neuAgTsqXOa6RJswhyn53cW4DwWg_g26lHJZXQvv_RHZRlQ

            把它復制到 jwt.io 上面看看

            圖片

            注意我綠色框選中的地方,里面是一段 JSON ,我們把它刪掉,看看輸入框的提示信息

            圖片

            這里提示了,里面是填寫(xiě)公鑰格式(通常為 PEM)或者 JWK (我們說(shuō)過(guò) RSA 算法是使用私鑰簽發(fā) JWT,公鑰進(jìn)行驗證),剛剛我們刪掉的是一段 JSON,所以必然不是公鑰格式,那是 JWK 嗎?

            當然是,JWK 的全稱(chēng)是 JSON Web Key ( RFC 7517[7] ) ,它就是一個(gè) JSON ,JWK 就是用 JSON 來(lái)表示密鑰(JSON 字段因密鑰類(lèi)型而異)。例如剛才刪除的 JWK :

            {
              "e""AQAB",
              "kty""RSA",
              "n""wVKQLBUqOBiay2dkn9TlbfuaF40_edIKUmdLq6OlvzEMrP4IDzdOk50TMO0nfjJ6v5830_5x0vRg5bzZQeKpHniR0sw7qyoSI6n2eSkSnFt7P-N8gv2KWnwzVs_h9FDdeLOeVOU8k_qzkph3_tmBV7ZZG-4_DEvgvat6ifEC-WzzYqofsIrTiTT7ZFxTqid1q6zrrsmyU2DQH3WdgFiOJVVlN2D0BuZu5X7pGZup_RcWzt_9T6tQsGeU1juSuuUk_9_FVDXNNCTObfKCTKXqjW95ZgAI_xVrMeQC5nXlMh6VEaXfO83oy1j36wUoVUrUnkANhp-dnjTdvJgwN82dGQ"
            }

            其中 kty 字段是必須的,代表密鑰類(lèi)型,支持 EC 橢圓曲線(xiàn)密鑰,RSA 密鑰和 oct 對稱(chēng)密鑰。

            JWK 和 公鑰格式 Pem 是可以互相轉換的:

            圖片

            我們現在已經(jīng)知道,驗證這個(gè) JWT 是需要公鑰或 JWK 的,那你會(huì )不會(huì )好奇 jwt.io 這個(gè)網(wǎng)站是怎么知道 JWK 的呢,為什么一粘貼,就自動(dòng)將 JWK 填充進(jìn)去了。

            原理其實(shí)很簡(jiǎn)單,而且已經(jīng)是一種大家都遵循的規范了,就是將 JWK 放在 iss/.well-known/jwks.json 下,其中 iss 就是 Payload 里面的 iss 。

            圖片圖片

            當你在 jwt.io 粘貼下 JWT 的瞬間,jwt.io 會(huì )先解析 Header ,判斷出 JWT 使用的算法(JWA),接著(zhù)解析出 Payload 的信息,由于這里是 RS256 算法, 所以還會(huì )去請求 Payload 里的 iss 下的 .well-known/jwks.json得到 JWK ,從而完成 JWS 的驗證。

            4)另一種 JWT 的實(shí)現 :JWE

            我們說(shuō)過(guò),經(jīng)過(guò) Signature 簽名后的 JWT 就是指的 JWS ,而 JWS 僅僅是對前兩部分簽名,保證無(wú)法篡改,但是其 Payload(載荷) 信息是暴露的(只是作了 base64UrlEncode 處理)。因此,使用 JWS 方式的 Payload 是不適合傳遞敏感數據的,JWT 的另一種實(shí)現 JWE 就是來(lái)解決這個(gè)問(wèn)題的。

            JWE 全稱(chēng)是 JSON Web Encryption ( RFC 7516[8] ) ,JWS 的 Payload 是 Base64Url 的明文,而 JWE 的數據則是經(jīng)過(guò)加密的。它可以使 JWT 更加安全。

            JWE 提供了兩種方案:共享密鑰方案和公鑰/私鑰方案。共享密鑰方案的工作原理是讓各方都知道一個(gè)密鑰,大家都可以簽名驗證,這和 JWS 是一致的。而公鑰/私鑰方案的工作方式就不同了,在 JWS 中私鑰對令牌進(jìn)行簽名,持有公鑰的各方只能驗證這些令牌;但在 JWE 中,持有私鑰的一方是唯一可以解密令牌的一方,公鑰持有者可以引入或交換新數據然后重新加密,因此,當使用公鑰/私鑰方案時(shí),JWS 和 JWE 是互補的。

            想要理解這一點(diǎn)的更簡(jiǎn)單的方法是從生產(chǎn)者和消費者的角度進(jìn)行思考。生產(chǎn)者對數據進(jìn)行簽名或加密,消費者可以對其進(jìn)行驗證或解密。對于 JWS ,私鑰對 JWT 進(jìn)行簽名,公鑰用于驗證,也就是生產(chǎn)者持有私鑰,消費者持有公鑰,數據流動(dòng)只能從私鑰持有者到公鑰持有者。相比之下,對于 JWE ,公鑰是用于加密數據,而私鑰用來(lái)解密,在這種情況下,數據流動(dòng)只能從公鑰持有者到私鑰持有者。如下圖所示(來(lái)源 JWT Handbook[9] ):

            圖片

            相比于 JWS 的三個(gè)部分,JWE 有五個(gè)部分組成(四個(gè)小數點(diǎn)隔開(kāi))。一個(gè) JWE 示例如下:

            eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.
            UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_
            i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKxYxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8Otv
            zlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTPcFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.
            AxY8DCtDaGlsbGljb3RoZQ.
            KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.
            9hH0vgRfYgPnAHOd8stkvw
            • Protected Header (受保護的頭部) :類(lèi)似于 JWS 的 Header ,標識加密算法和類(lèi)型。
            • Encrypted Key (加密密鑰) :用于加密密文和其他加密數據的密鑰。
            • Initialization Vector (初始化向量) :一些加密算法需要額外的(通常是隨機的)數據。
            • Encrypted Data (Ciphertext) (加密的數據) :被加密的數據。
            • Authentication Tag (認證標簽) :算法產(chǎn)生的附加數據,可用于驗證密文內容不被篡改。

            這五個(gè)部分的生成,也就是 JWE 的加密過(guò)程可以分為 7 個(gè)步驟:

            1. 根據 Header alg 的聲明,生成一定大小的隨機數

            2. 根據密鑰管理方式確定 Content Encryption Key ( CEK )

            3. 根據密鑰管理方式確定 JWE Encrypted Key

            4. 計算所選算法所需大小的 Initialization Vector (IV)。如果不需要,可以跳過(guò)

            5. 如果 Header 聲明了 zip ,則壓縮明文

            6. 使用 CEK、IV 和 Additional Authenticated Data ( AAD,額外認證數據 ) ,通過(guò) Header enc 聲明的算法來(lái)加密內容,結果為 Ciphertext 和 Authentication Tag

            7. 最后按照以下算法構造出 Token:

              base64(header) + '.' +
              base64(encryptedKey) + '.' + // Steps 2 and 3
              base64(initializationVector) + '.' + // Step 4
              base64(ciphertext) + '.' + // Step 6
              base64(authenticationTag) // Step 6

            JWE 相比 JWS 更加安全可靠,但是不夠輕量,有點(diǎn)復雜。

            5)安全性考慮

            不管怎樣,JWT 多多少少還是存在一些安全性隱患的,下面是平時(shí)開(kāi)發(fā)過(guò)程的一些建議:

            1. 始終執行算法驗證

              簽名算法的驗證固定在后端,不以 JWT 里的算法為標準。假設每次驗證 JWT ,驗證算法都靠讀取 Header 里面的 alg 屬性來(lái)判斷的話(huà),攻擊者只要簽發(fā)一個(gè) "alg: none" 的 JWT ,就可以繞過(guò)驗證了。

            2. 選擇合適的算法

              具體場(chǎng)景選擇合適的算法,例如分布式場(chǎng)景下,建議選擇 RS256 。

            3. HMAC 算法的密鑰安全

              除了需要保證密鑰不被泄露之外,密鑰的強度也應該重視,防止遭到字典攻擊。

            4. 避免敏感信息保存在 JWT 中

              JWS 方式下的 JWT 的 Payload 信息是公開(kāi)的,不能將敏感信息保存在這里,如有需要,請使用 JWE 。

            5. JWT 的有效時(shí)間盡量足夠短

              JWT 過(guò)期時(shí)間建議設置足夠短,過(guò)期后重新使用 refresh_token 刷新獲取新的 token 。

            6)總結

            今天為大家講了一些 JWT 不為人知的秘密,總結一下涉及到的知識點(diǎn):

            • JOSE:規范網(wǎng)絡(luò )傳輸過(guò)程中使用 JSON 的一系列標準
            • JWT:以 JSON 編碼并由 JWS 或 JWE 安全傳遞的表示形式
            • JWS:簽名和驗證 Token
            • JWE:加密和解密 Token
            • JWA:定義 JOSE 體系中涉及到的所有算法
            • JWK:用 JSON 來(lái)表示密鑰

            最后,再次附上 JOSE 的體系圖,相關(guān)的 RFC 均備注在圖上了:

            圖片



            關(guān)鍵字: JWT

            文章連接: http://www.gostscript.com/cjwt/785.html

            版權聲明:文章由 晨展科技 整理收集,來(lái)源于互聯(lián)網(wǎng)或者用戶(hù)投稿,如有侵權,請聯(lián)系我們,我們會(huì )立即刪除。如轉載請保留

            双腿国产亚洲精品无码不卡|国产91精品无码麻豆|97久久久久久久极品|无码人妻少妇久久中文字幕
                1.