Identity Server4 基礎應用(四)Hybrid Flow與PKCE


前言

前文介紹了Authorization Code flow的基本內容,可以看出其擁有不錯的安全機制。但是仍然存在局限,如果客戶端是運行在服務器上的Web應用程序(這類客戶端稱為機密客戶端)當然是個不錯授權模式,因為很多涉及安全隱患的步驟(如AccessToken)都是通過后端通道由web服務器和授權服務器直接通信的,而不需要經過用戶的瀏覽器或者其他的地方。雖然如此,但是Authorization Code仍然是通過前端通道傳遞的,如果code被泄露,就仍然存在安全隱患,典型的有Cut and pasted code attack,就是一種盜用code的攻擊來獲取用戶的權限。因此,官方更加建議使用“Hybrid Flow”或“PKCE”從而增加安全性,但是官方更加推薦使用PKCE。

Hybrid Flow

先介紹一下ID_Token具體是什么,ID_Token就像我們的身份證或者戶口本,客戶端程序可以通過ID_Token獲取用戶的ClaimsID_Token由三個部分(頭Header,體Body和簽名Signature)組成並且是通過JWT形式呈現。ID_Token中包含的主要內容有issIssuing authority)、subA unique identifier for the end-user issued by the issuer)、audexpiatauth_time等。

Hybrid Flow在流程上大致是和Authorization Code flow一樣的,唯一的區別是在完成用戶的身份認證之后,通過authorization endpoint返回的數據不同。而這一步返回的數據是根據我們發送請求時的response_type參數決定的,這使得流程更加靈活。

Hybrid Flow根據response_type的不同,authorization endpoint返回可以分為三種情況。

  1. response_type = code + id_token ,即包含Authorization Codeidentity Code
  2. response_type = code + token ,即包含Authorization CodeAccess Code
  3. response_type = code + id_token + token,即包含Authorization Codeidentity CodeAccess Token

可以看到,code都是一定會返回的。如果ID_Tokenauthorization endpointtoken endpoint都被返回了,那么

  • iss和sub的值必須是相同的
  • 所有關於身份認證的Claims在兩者中應該都包含
  • 但是authorization endpoint返回的Claim數量應該會少一點,這也是出於對隱私的考慮

如果Access Tokenauthorization endpointtoken endpoint都被返回了,那么

  • 那么兩次值可能相同也可能不同
  • 這都是取決於這兩個終結點的安全特性

那么到底為什么要使用hybrid flow呢?讓我們的應用程序在前端通道和后端通道都可以接收到分開的token接下來進行一些簡單的實踐,有了前面AuthorizationCode模式代碼的經驗,編寫Hybrid Flow也是很簡單的。

授權服務器上新增HybridClient

在之前代碼的基礎上,新增一個授權方式是Hybridclient,這樣就ok了。

創建一個Hybrid流程的MVC客戶端

創建一個新的ASP.NET Core MVC程序,取名為“MVC_Hybrid”,使用Nuget添加IdentityModelOpenIdConnect的引用。

Startup.cs中進行配置,代碼和Authorization Code Flow的基本一致,只是我們在配置ResponseType時需要使用Hybrid定義的三種情況之一,具體代碼如下。

隨后在Controller中,和前面介紹Authorization Code時一樣,我們通過擴展方法在授權過程中獲取的幾個token,並顯示到界面上

 1 public async Task<IActionResult> Index()
 2         {
 3             //我們利用拓展方法獲取存下來的Access Token
 4             var accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
 5             ViewBag.idToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.IdToken);
 6             var client = new HttpClient();
 7             //攜帶上AccessToken
 8             client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
 9             //去請求受保護的api1上的資源
10             var response = await client.GetAsync("http://localhost:5001/identity");
11             if (!response.IsSuccessStatusCode)
12             {
13                 ViewBag.Json = response.ReasonPhrase;
14             }
15             var content = await response.Content.ReadAsStringAsync();
16             ViewBag.Json = JArray.Parse(content).ToString();
17             return View();
18         }
Controller中Index
1 @{
2     ViewBag.Title = "Json";
3     Layout = "_Layout";
4 }
5 <p>@ViewBag.idToken</p>
6 <pre>@ViewBag.Json</pre>

以上,准備工作就已經完成了。接下來運行授權服務器和mvc客戶端,運行成功后使用內置的用戶登錄,完成授權后進入獲取到數據。

在整個過程中,我們使用Fiddler抓取請求,可以看到在Authorization Endpoint同時返回了codeid_token

使用https://jwt.io/解析Authorization EndPoint返回的Id_TokenToken EndPoint返回的id_Token,可以看到其中包含的用戶信息都是一樣的。

關於Hybrid Flow的其他兩種模式也類似,我們只需要在客戶端的修改請求時的ResponseType即可,就不再贅述了。

在使用Hybrid時我們看到授權終結點返回的Id Token中包含at_hashAccess Token的哈希值)和c_hashCode的哈希值),規范中定義了以下的一些檢驗規則。

  1. 兩個id_token中的 iss 和 sub 必須相同。
  2. 如果任何一個 id token 中包含關於終端用戶的聲明,兩個令牌中提供的值必須相同。
  3. 關於驗證事件的聲明必須都提供。
  4. at_hash 和 c_hash 聲明可能會從 token 端點返回的令牌中忽略,即使從 authorize 端點返回的令牌中已經聲明。

Proof Key for Code Exchange

在授權過程中,Authorization Code通過前端通道傳遞有被泄露的風險,在Hybrid FlowId_Token也在前端通道傳遞的同時也將用戶數據暴露了出來。因此這里介紹的Proof Key for Code Exchange(PKCE) 就是用來降低威脅的一種方法。概括下PKCE參與在授權驗證中的主要流程。

  1. 客戶端在請求code前隨機生成一段字符串,稱為code_verifier
  2. code_verifier通過加密算法生成加密后的字符串,稱為code_challenge
  3. 當客戶端在向授權服務器的授權終結點請求code的同時發送code_challenge給授權服務器,同時為了告訴服務器我使用的是什么加密算法,將算法標識放在
  4. code_challenge_method中;
  5. 當客戶端使用codeToken終結點請求AccessToken的同時會發送code_verifier
  6. 授權服務器使用相同的加密算法將code_verifier變換后與之前收到的code_challenge比對,比對成功才會發放Access Token

再畫一個簡圖直觀的看一下上面的流程。

 其實在第二篇文章中其實我們已經看到了這個方法的影子,在Fiddler查看授權請求時我們看到了code_challengcode_challenge_methodcode_verifier,這是因為我們在配置OpenIdConnect時對PKCE的支持是默認開啟的,只不過當時我們沒有在授權服務器端打開驗證。

那么在授權服務器端我們如何開啟使用PKCE驗證呢,也很簡單,在對client進行配置時,只需添加一句配置。

1 AllowedGrantTypes = GrantTypes.Code,
2 RequirePkce = true,  //開啟PCKE

根據官方的說法,還是更加推薦使用PKCE。因為涉及到的加密過程都需要在客戶端中實現,相比Hybrid模式實現PKCE的客戶端就十分簡潔,並且也在前端通道中增加其他的響應元素,最主要的還是因為在實現起來,PKCE更加簡單,在ASP.NET Core3開始后已經增加了對PKCE的默認支持,只需簡單的一句設置(RequirePkce = true)就能搞定了。

參考資料:

https://identityserver4.readthedocs.io/en/latest/topics/grant_types.html 

https://medium.com/identity-beyond-borders/openid-connect-hybrid-flow-1123bc9461fe 

https://tools.ietf.org/html/rfc7636 

https://tonyxu.io/zh/posts/2018/oauth2-pkce-flow/ 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM