­

JWT到底是個什麼鬼?

前面一篇我們了解了微服務安全認證架構是如何演進而來的,但是發現v2.5架構仍然較重,有沒有輕量級一點的方法呢?其實業界早已有了實踐,它就是基於JWT的安全認證架構。JWT到底是個什麼鬼呢?本篇為你解答!

1、V2.5版本架構存在的問題

在v2.5版本Token+Gateway模式下,適合於大部分微服務場景,但是當網站流量很大的時候,對AuthService的訪問壓力也會比較大,它很可能會成為性能和擴展性的瓶頸

MyShop v2.5版本:Token+Gateway

此外,對於很多對於安全不是很敏感的微服務來說,集中狀態校驗就會顯得很笨重。

2、V2.6版本:JWT+Gateway

在業界實踐上,很多企業都在採用基於JWT令牌的無狀態安全認證架構,MyShop技術團隊也探索出了v2.6版本,即基於JWT+Gateway的模式:

MyShop v2.6:JWT+Gateway

v2.6在v2.5的基礎之上發展而來,主要區別如下:

(1)第二步中,v2.5使用的是透明應用令牌,而v2.6使用的是JWT令牌,JWT令牌是自包含數據和簽名的;

(2)第四步和第五步,v2.5需要網關每次請求都去AuthService進行校驗,而v2.6網關處則不用;此處,網關就可以自行進行令牌的解析和合法性校驗;解析完成後,網關就可以得到用戶標識資訊並向後端微服務傳遞了;

畫外音:這裡的JWT令牌有點類似於單塊架構階段v1.x版本下的無狀態Session,並且針對於微服務場景進行了擴展應用。

JWT+Gateway的這種做法簡化了安全認證架構,降低了AuthService的壓力,總體上來說是一種高性能和可擴展的架構,適用於大部分對安全要求不太敏感的微服務應用場景。為什麼說是大部分對安全要求不敏感的場景呢,這就需要我們了解一下JWT的原理了。

3、JWT的原理

JWT全程JSON Web Token,是一種用於通訊雙方之間傳遞安全資訊的簡潔的、URL安全的表述性聲明規範,經常用在跨域身份驗證。JWT最主要的特點就是它定義了一種緊湊和自包含的JSON對象格式,通過它可以在多個系統或服務之間安全的傳遞資訊,資訊經過數字簽名可以校驗且是可信任的。JWT主要用於 認證授權 和 資訊交換 的場景,其令牌結構主要有如下圖所示的3個部分組成,且不同部分之間用了一個 . 分隔:

JWT的三個組成部分

這三個組成部分分別是:Header頭部、Payload消息體 以及 Signature簽名。

畫外音:JWT將消息體分為了Header和Payload,其實有點類似於HTTP協議,它也將請求體分為了Header和Body,Header裡面一般放元數據,類似於信封上的寄件人和地址等,而Body裡面則存放的是實際數據,類似於信封裡面的主體內容。

下面我們來看一個JWT令牌的示例:

JWT令牌示例

我們先關註上圖中的左半部分,可以看到,三個部分分別使用了不同的顏色標註了出來,並且通過 . 分隔開。
畫外音:如果你沒看到,那就仔細看一下!如果還沒看到,那就打開放大看一下!

一般來說,我們都會通過一些工具例如jwt.io網站來查看JWT解碼後的內容,也就是上圖中的右半部分就是在jwt.io上進行解碼後的內容。

可以看到,Header部分解碼後的內容說明了這個令牌的類型是JWT,即JSON Web Token,它使用的演算法是HS256演算法。

然後,Payload部分解碼後的內容說明了這個令牌的頒發者是誰(iss),頒發的時間(iat),令牌過期時間(exp)、這個令牌要頒發給誰(aud)以及目標用戶是誰(sub)。這些資訊也稱為Claims,他們是官方定義的Public Claims。我們在實際使用中,也會定義一些Custom Claims,比如用戶的角色資訊(Role)等。

對於使用ASP.NET Core的開發童鞋,推薦閱讀曉晨的這篇文章實踐IdentityServer:《IdentityServer4實戰-基於角色的許可權控制及Claim詳解》。

最後,Signature部分則表明了整個JWT的驗證方式是什麼樣子的,即一個簽名公式。如果是採用HS256演算法的話,就是下面這個公式:

base64Url(Header)+"."+base64Url(Payload)+"."+base64Url(Signature)

在jwt.io上,我們可以通過輸入secret進行一個令牌的合法性的校驗,如果不通過則會顯示Invalid Signature,通過則顯示Signature Verified.

JWT令牌校驗

看完了JWT的三個組成部分,及其組裝公式,我們可能會發現:Header和Payload的內容是公開可見的,只要拿到Token就可以去類似jwt.io這種工具網站上進行Debug解析,那JWT真的安全嗎?

畫外音:JWT保證的安全可能是相對的,它不會保證傳輸資訊的保密性,但它會保證資訊的可依賴和不可篡改性(通過Signature實現)。因為Secret是保密的,所以即使一般用戶拿到了你的token和演算法,也無法篡改裡面的數據(一旦篡改校驗就會不通過)。換句話說,JWT令牌有點類似於現實世界中的簽名支票,如下圖所示。

簽名支票

4、JWT的實現方式

上面我們了解了JWT的原理,現在來看看JWT都是如何來實現的。目前,JWT主要有兩種演算法實現,一種是HMAC,另一種是RSA。

HMAC流程

首先,來看看HMAC的實現流程:

HAMC流程

Step1.客戶端向AuthServer發出登錄請求;

Step2.AuthServer校驗用戶身份,通過後生成JWT數據結構且採用某種HMAC演算法+Secret對JWT進行簽名,最後將這個簽名後的JWT令牌返回給客戶端;

Step3.客戶端收到JWT後一般都會做本地存儲,然後在調用微服務的時候都會帶上JWT令牌;

Step4.微服務接收到客戶端請求和JWT令牌時,會採用同樣的Secret對JWT令牌進行解析和校驗,通過後則返回處理後的數據,不通過則一般返回401。

由此看來,HMAC流程中,最重要的就是secret的保密,如果泄露,則整個流程不再安全。

RSA流程

然後,來看看RSA的實現流程:

RSA流程

RSA流程總體上來說和HMAC類似,不同的是AuthServer在頒發JWT令牌的時候採用私鑰Private Key進行簽名,而微服務端ResourceServer在解析和校驗JWT令牌的時候採用公鑰Public Key進行簽名。
可以看出,RSA流程比HMAC流程總體來說要安全一點,因為只有AuthServer一個地方需要保存私鑰,私鑰的泄露概率就小很度。其他的微服務端都使用公鑰進行解簽校驗,但是不能夠篡改加簽。

畫外音:其實就類似於對稱加密 和 非對稱加密的方式。

5、JWT學習小結

本文通過MyShop v2.5存在的問題引出了使用JWT令牌的v2.6架構,並介紹了JWT的概念、原理 和 實現方式。最後,我們來總結一下JWT的優勢及不足:

我們重點關注一下JWT的不足:

(1)無狀態和吊銷無法兩全,如果某個用戶令牌異常(比如有黑客在幹壞事),我們想要吊銷這個用戶的令牌,但是卻沒有辦法在AuthService上進行統一弔銷,一般需要等到這個JWT令牌自然過期才能吊銷。又假設我們在AuthService上對某個用戶的資訊進行了更新,那麼相關的Claims資訊也必須要等到這個老的JWT過期後重新登錄或刷新後產生了新的JWT後才能更新。

(2)JWT的大小會隨著Claims的數量增多,也會導致JWT的大小會變大,從而也會導致傳輸的開銷增大。最後,我們可以對有狀態的透明令牌和無狀態的JWT令牌做一個小結:兩者各有適用場景,JWT令牌更適合於安全不敏感場景,透明令牌更適合於安全敏感場景。這裡的敏感主要是指和錢、交易、支付相關的場景,以及金融、銀行等業務之類的場景,這些場景可以採用集中式的有狀態的透明令牌認證,其他的一般性的微服務應用場景則可以使用JWT。

畫外音:對中小技術團隊來說,特別是技術儲備和實力都沒那麼強的團隊,和錢相關的業務場景,寧慢三秒,不搶一秒,因為有時候想快那麼一秒,可能就翻車了。