IdentityServer4實戰 - 談談 JWT 的安全策略

一.前言

衆所周知,IdentityServer4 默認支持兩種類型的 Token,一種是 Reference Token,一種是 JWT Token 。前者的特色是 Token 的有效與否是由 Token 頒發服務集中化控制的,頒發的時候會持久化 Token,而後每次驗證都須要將 Token 傳遞到頒發服務進行驗證,是一種中心化的比較傳統的驗證方式。JWT Token 的特色與前者相反,每一個資源服務不須要每次都要都去頒發服務進行驗證 Token 的有效性驗證,該 Token 由三部分組成,其中最後一部分包含了一個簽名,是在頒發的時候採用非對稱加密算法(最新的JWT Token)進行數據簽名的,保證了 Token 的不可篡改性,保證了安全,與頒發服務的交互,僅僅是獲取公鑰用於驗證簽名,且該公鑰獲取之後能夠本身緩存,持續使用,不用再去交互得到,除非Token包含的 keyid 對應的 公鑰沒被緩存(新的),就會再次向頒發服務獲取。我畫了一張流程圖,你們能夠去查看:http://www.javashuo.com/article/p-oerarhqa-bg.htmlhtml

這裏說一下我在文章說所說的名詞:算法

頒發服務:即生成Token的服務。數據庫

資源服務:提供給用戶訪問的API資源緩存

二.JWT Token 的安全問題

前言中有過敘述,JWT 類型的 Token 在驗證的時候,無需依靠頒發服務來驗證 Token 的有效性,是一種去中心化的驗證方式,這就意味着頒發服務沒法集中控制 Token。假如 Token 暴露之後,在 Token 有效期內,將會一直被人惡意使用,這時候該怎麼辦呢?這裏主要從兩個方面來說,一個是儘可能避免被惡意獲取Token,一個是被惡意獲取了怎麼控制失效。請聽下面分解。安全

1.使用 HTTPS

此種方式是避免被人獲取惡意獲取Token。服務器

HTTPS 在傳輸數據時,數據內容是加密的,能夠有效避免中間人攻擊,因此在使用 JWT Token 的程序建議都採用HTTPS。分佈式

img

2.添加自定義Token失效機制

此種方式是被惡意獲取了怎麼控制失效。性能

由於 IdentityServer4 對 JWT Token,默認是沒有控制失效的機制的,因此若是咱們想添加這種機制,只有咱們自定義,下一節作詳細介紹。網站

三.自定義Token失效機制

1.簡單黑名單模式

顧名思義,就是添加一個 Token 黑名單,這個黑名單建議存在諸如 Redis 等分佈式緩存,數據庫等介質,可讓全部資源服務共同訪問。不推薦添加在資源服務本地緩存,若是這樣作,那麼每次添加黑名單還須要同步到每一個資源服務。每一個資源服務在每次驗證Token的時候須要查詢一下黑名單,若是在黑名單裏面,即 Token 無效。加密

2.進階黑名單模式

前面小節的 【簡單黑名單模式】 有一個很是大的弊端,就是每一個 Token 驗證時都須要去驗證是否在黑名單,正常狀況下,咱們正常的Token 是佔絕大多數的,若是用此種機制,那麼對資源是一種很大的浪費。那麼咱們須要設立一種機制,來讓咱們認爲 可疑 的Token進行黑名單驗證,那麼如何來判斷Token是否可疑呢,我這裏想了一種方式。

如何判斷 Token 是否可疑:

咱們在生成Token的時候,能夠添加自定義 Claim (身份信息單元),那麼咱們能夠參考網站登陸的安全機制,那麼咱們能夠添加一個用戶ip的Claim,這樣咱們生成的Token都會攜帶用戶生成Token時的IP,咱們每次驗證Token是否有效時,就能夠根據客戶端來源IP與Token攜帶的IP進行匹配,若是匹配不上,那麼該Token咱們就能夠認爲是可疑的,從而進行黑名單的驗證。

該方式相對於前面的 【簡單黑名單模式】模式算是一個比較好的進階了。

在這裏,咱們還須要考慮到IP做爲用戶的私密信息,咱們將IP放入Token時,須要對IP進行加密。由於 JWT Token 前兩部分,僅僅是 base64 Encode 而已。

Claim 詳解請參考 http://www.cnblogs.com/stulzq/p/8726002.html

3.強化黑名單模式

不管是【簡單黑名單模式】仍是【進階黑名單模式】,咱們在對比黑名單時是對token進行徹底比對,這樣的方式,在某些場景就存在侷限性,比我想讓該用戶在某某時間之前頒發的Token都算做黑名單。因此咱們在判斷黑名單時能夠根據用戶id以及token頒發時間來判斷。若是讓規則自動失效?咱們能夠用前面設定的 token頒發時間加上咱們頒發服務設置的token有效時間就等於規則失效時間。

4.將Token添加進黑名單的方式

咱們前面設立了黑名單模式,那麼咱們的Token什麼時候加入黑名單呢,難道讓用戶說,個人 Token 被盜了,你把個人 Token加入黑名單吧,這確定不現實。咱們能夠在退出登陸時,就自動往黑名單添加一條規則,採用【強化黑名單模式】添加用戶id以及當前時間做爲token頒發時間來驗證。好比用戶id1000,此用戶在 2018-09-20 12:11 退出,咱們就能夠添加一條規則 userid=1000,tokenissuetime=2018-09-20 12:11 ,該規則表示只要用戶id爲1000的而且token頒發時間小於2018-09-20 12:11的token,都被算做黑名單token。

這時有人可能會說,這個token若是仍是這個用戶再次拿來使用,那仍是有效的,你這個怎麼沒讓他失效呢?咱們設立黑名單模式就是爲了不用戶的還在有效期的Token被他人惡意使用。對於用戶本身來講,這個問題就可有可無了。

5.所有 Token 失效的機制。

所有Token失效的方式,目前我想了兩種:

1.更換頒發服務的密鑰對,而且重啓全部資源服務(資源服務獲取的公鑰默認存在內存,重啓能夠丟失)。這樣本來的Token在驗證時,將會找不到對應的公鑰,致使驗籤失敗從而Token無效。

2.相似於前面【強化黑名單模式】的驗證黑名單的方式,咱們能夠在驗證Token的流程中加兩個配置,一個是控制這種配置是否開啓的開關,一個是某個時間,規則就是若是在這個時間之前頒發Token所有算做無效Token。這種就須要資源服務支持熱加載配置,從而避免重啓資源服務。

我我的推薦第二種方式。

四.其餘解決方案

這裏的內容是根據評論整理的,我我的的想法不可能面面俱到,因此整理了一下評論裏比較不錯的方案:

Savorboard:

JWT 的最佳實踐是遵循默認的過時策略(15分鐘過時), 他可以有效的保證Token的有效性。 刷新Token是爲了保證身份驗證的服務端與授予令牌的客戶端在訪問權限方面保持一致,好比Claim裏可能包含最新的訪問權限,這是一個必要且必須的過程。

因此,頻繁的15分鐘刷新令牌是有必要的,這並不足以對服務器的性能產生很大的影響。

五.寫在最後

文中所訴是總結了我長久以來的想法,token加入ip還有根據id和頒發時間驗證黑名單都是我今天無心間想到的。若是你閱讀了本文有什麼不明白或者你認爲有改進的地方,或者更好的地方,歡迎在評論與我交流。本文的問題,有不少人問過我,也討論了很多,我相信不少人在使用ids4是可能會有這樣的問題,因此在此發表了個人一個觀點,但願能給你參考,後續的文章我會根據這個想法來實現。

相關文章
相關標籤/搜索