日韩国产精品99成人不卡在线无毒|狠狠躁夜夜爽一级二级精品|亚洲日日噜噜孕妇中文字幕|日韩久草中文三级片

新聞動態(tài)

你可能沒那么了解 JWT

常見問題 發(fā)布者:ou3377 2021-12-08 09:04 訪問量:261

圖片

0)前言

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

1)我們最常使用的 JWT

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

圖片

這種方案有一些缺點:

  • 需要從內(nèi)存或數(shù)據(jù)庫里存取 session 數(shù)據(jù)
  • 擴展性差,對于分布式應(yīng)用,需要實現(xiàn) session 數(shù)據(jù)共享

JWT 正好可以解決這些問題:

圖片

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

一個簡單的 JWT 示例如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIyMDIxLTEwLTI0IDAwOjAwOjAwIiwibmFtZSI6InRvZ2V0dG95b3UifQ.XdF46NflSUjnt-adAc6rNZEXI1OD6nxtwGuhz9qkxUA

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

圖片

可以看出 JWT 以不同顏色區(qū)分,兩個小數(shù)點隔開,分為了三部分

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

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

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

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

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

2)JOSE 規(guī)范

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

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

圖片

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

3)JWA 和 JWS 以及 JWK

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

說了那么多,好像都沒有正式介紹過 JWS 。JWS 的全稱是 JSON Web Signature ( RFC 7515[6] ) ,它的核心就是簽名,保證數(shù)據(jù)未被篡改,而檢查簽名的過程就叫做驗證。更通俗的理解,就是對應(yīng)前面提到的 JWT 的第三部分 Signature ,所以我才會說我們?nèi)粘K褂玫?JWT 都是 JWS 。

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

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

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

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

把它復(fù)制到 jwt.io 上面看看

圖片

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

圖片

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

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

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

其中 kty 字段是必須的,代表密鑰類型,支持 EC 橢圓曲線密鑰,RSA 密鑰和 oct 對稱密鑰。

JWK 和 公鑰格式 Pem 是可以互相轉(zhuǎn)換的:

圖片

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

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

圖片圖片

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

4)另一種 JWT 的實現(xiàn) :JWE

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

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

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

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

圖片

相比于 JWS 的三個部分,JWE 有五個部分組成(四個小數(shù)點隔開)。一個 JWE 示例如下:

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

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

  1. 根據(jù) Header alg 的聲明,生成一定大小的隨機數(shù)

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

  3. 根據(jù)密鑰管理方式確定 JWE Encrypted Key

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

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

  6. 使用 CEK、IV 和 Additional Authenticated Data ( AAD,額外認證數(shù)據(jù) ) ,通過 Header enc 聲明的算法來加密內(nèi)容,結(jié)果為 Ciphertext 和 Authentication Tag

  7. 最后按照以下算法構(gòu)造出 Token:

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

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

5)安全性考慮

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

  1. 始終執(zhí)行算法驗證

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

  2. 選擇合適的算法

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

  3. HMAC 算法的密鑰安全

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

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

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

  5. JWT 的有效時間盡量足夠短

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

6)總結(jié)

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

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

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

圖片



關(guān)鍵字: JWT

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

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