1. 程式人生 > 實用技巧 >基於Identity Server4的OAuth 2.0授權總結(4)- PKCE in Authorization Code mode

基於Identity Server4的OAuth 2.0授權總結(4)- PKCE in Authorization Code mode

授權碼模式的過程大致是如下圖所示:

在獲取token的時候需要提供如下資訊:

1. code

2. redirect_url,

3. client_id,client secret

第二項和第三項其實是用來對通過code獲取token的client的合法性進行驗證。其中最核心的應該是client secret。通過他可以解決如下問題:

對獲取token的client進行合法性驗證。secret是在Authorization Server上註冊client的時候設定的,只有client自己知道,因此可以對client進行驗證。

這樣的話,即使code因為某種原因洩露了,沒有secret也無法獲取到token。從而提升了安全性。在傳統的Web應用中,token的獲取是發生在後端,因此secret也是儲存在後端。這樣是可行的。但是對於現在比較流行的SPA應用,token的獲取是發生在瀏覽器端,是一個公開的環境。這個方法就不可行了,因為secret不可能儲存在一個公開的環境中。

在這個場景下,就需要用PKCE(Proof Key for Code Exchange)來保證整個過程的安全性了。

PKCE主要是通過在授權的過程中增加了code_challenge和code_verifier兩個元素來對整個流程進行驗證,防止code被第三方擷取的情況。具體流程如下:

這裡面最核心的其實就是在authorize請求中增加了code_challenge引數,在token請求中增加了code_verifier引數。這兩個引數最終都是依賴於一個client生成的隨機字串。

Random String:是一個Client端生成的隨機字串(由字母,數字,- ,. ,_ ,~ 組成)

code_verifier:Random String
code_challenge引數的生成演算法為:BASE64URL-ENCODE(SHA256(ASCII(Random String)))。
過程解析:

1. 在申請授權時(authorize請求),client,生成隨機字串並基於它生成code_challenge傳給authorization server.(這個過程中random string 在網路中不會被暴露,因為對其進行了hash)。

2. authorization server生成授權碼後,會將code_challenge儲存起來,並與授權碼關聯。

3. 在通過授權碼獲取token的過程中,client會將隨機字串(code_verifier)傳給authorization server

4. authorization server會將code_verifier進行與第一步相同演算法進行計算得到新的code_challenge

5. authorization server將第四步中的code_challenge與第一步中的原始code_challenge進行比較,如果相同則認為申請授權的源與用code獲取token的源為同一來源。(即code沒有被第三方擷取而冒用)

實現:
服務端

Identity Server 4預設支援PKCE模式,但是是可選的(就是說client也可以不使用該方式)。如需強制client使用PKCE,只需在定義Client時將Client配置成RequirePkce即可。

new Client
                {
                    ClientId = "js",
                    RequireConsent = false,
                    AllowedGrantTypes = GrantTypes.Code,
                    RequireClientSecret = false,
                    RequirePkce = true,
                    AllowAccessTokensViaBrowser = false,
                    AlwaysIncludeUserClaimsInIdToken = true,
                    RedirectUris = new List<string>{"http://localhost:3000/callback.html"},
                    AllowedScopes = new List<string>{"api", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Email, "profile"},
                    PostLogoutRedirectUris = new List<string>{ "http://localhost:3000" }
                },

客戶端

客戶端oidc-client庫預設會採用PKCE,也不需要額外的配置。

總結
1. 傳統Web應用的client secret是儲存在後端,不會被洩露。因而可以用於驗證client,保護code被冒用的情況。對於public client(SPA),用於傳統Web應用的secret方式不再有效。

2. PKCE通過在每個授權請求過程中新增一個隨機secret,達到了了防止授權碼被冒用,同時secret不被洩露。

3. 對於public client, PKCE目前是推薦的認證模式。