天天看點

IdentityServer4實戰 - 談談 JWT Token 的安全政策

一.前言

衆所周知,IdentityServer4 預設支援兩種類型的 Token,一種是 Reference Token,一種是 JWT Token 。前者的特點是 Token 的有效與否是由 Token 頒發服務集中化控制的,頒發的時候會持久化 Token,然後每次驗證都需要将 Token 傳遞到頒發服務進行驗證,是一種中心化的比較傳統的驗證方式。JWT Token 的特點與前者相反,每個資源服務不需要每次都要都去頒發服務進行驗證 Token 的有效性驗證,該 Token 由三部分組成,其中最後一部分包含了一個簽名,是在頒發的時候采用非對稱加密算法(最新的JWT Token)進行資料簽名的,保證了 Token 的不可篡改性,保證了安全,與頒發服務的互動,僅僅是擷取公鑰用于驗證簽名,且該公鑰擷取以後可以自己緩存,持續使用,不用再去互動獲得,除非Token包含的 keyid 對應的 公鑰沒被緩存(新的),就會再次向頒發服務擷取。我畫了一張流程圖,大家可以去檢視:

https://www.cnblogs.com/stulzq/p/9226059.html

這裡說一下我在文章說所說的名詞:

頒發服務:即生成Token的服務。

資源服務:提供給使用者通路的API資源

二.JWT Token 的安全問題

前言中有過叙述,JWT 類型的 Token 在驗證的時候,無需依靠頒發服務來驗證 Token 的有效性,是一種去中心化的驗證方式,這就意味着頒發服務無法集中控制 Token。假如 Token 暴露以後,在 Token 有效期内,将會一直被人惡意使用,這時候該怎麼辦呢?這裡主要從兩個方面來講,一個是盡量避免被惡意擷取Token,一個是被惡意擷取了怎麼控制失效。請聽下面分解。

1.使用 HTTPS

此種方式是避免被人擷取惡意擷取Token。

HTTPS 在傳輸資料時,資料内容是加密的,可以有效避免中間人攻擊,是以在使用 JWT Token 的程式建議都采用HTTPS。

IdentityServer4實戰 - 談談 JWT Token 的安全政策

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

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

因為 IdentityServer4 對 JWT Token,預設是沒有控制失效的機制的,是以如果我們想添加這種機制,隻有我們自定義,下一節做詳細介紹。

三.自定義Token失效機制

IdentityServer4實戰 - 談談 JWT 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是可能會有這樣的問題,是以在此發表了我的一個觀點,希望能給你參考,後續的文章我會根據這個想法來實作。