Try   HackMD
tags: keycloak Tool

二、OIDC(Open ID Connect) vs SAML((Security Assertion Markup Language)

在這部分,我們將探討OIDC和SAML。正如前一章節所提,身分驗證和授權是整個安全流程中非常關鍵的環節。一般來說,會有專門的解決方案來處理這些問題。OIDC和SAML都是為這個目的而設計的標準協議,它們提供一個集中式的方法來驗證使用者身份,並界定他們可以訪問哪些資源或執行哪些操作。

1. Open ID Connect (OIDC):

OIDC是一個建立在OAuth 2.0之上的身分認證層。OAuth 2.0本身是一個專注於授權的框架,而OIDC則在這個基礎上增加了身分驗證功能。這樣,應用程式不僅能知道使用者有哪些權限,還能瞭解使用者是誰,並獲取他們的基本資訊,比如名稱和電子郵件地址。

a. OAuth 2.0

OAuth 2.0 是一個授權框架,允許第三方應用程式在使用者同意的情況下存取使用者在某個服務上的資訊,而不需要分享使用者的密碼。通常在OAuth 2.0,會有幾個角色,我們這邊舉一個簡單情境,你希望使用「快速日記」App,而這個App提供使用Google帳戶登入的功能來使用Google雲端硬碟服務。

  • Resource Owner(資源擁有者) : 通常就是User(你), 能授予應用程式取得受保護資料的人,通常就是終端使用者(end-user)。例如你希望使用「快速日記」App,而這個App提供使用Google帳戶登入的功能。在OAuth的流程中,當App請求許可存取你的資料時,你會給予(或拒絕)這個請求。

  • Resource Server(Resource Server) : 存放使用者受保護資料的伺服器,以這個例子來說就是Google雲端硬碟,當「快速日記」App希望保存或讀取日記時,它會向此伺服器提出請求。

  • Client (客戶端):通常指稱想要取得受保護資源的「應用程式」,以這個例子來說就是「快速日記」App。 當「快速日記」App希望保存或讀取日記時,它會向此伺服器提出請求。

  • Authorization Server (授權伺服器) : 驗證 Resource Owner 的身份,並且在獲得同意之後,發放「Access Token」給應用程式(Client)的伺服器。以這個例子來說就是 (Google的授權伺服器)。

下圖整個驗證Flow

驗證Flow
    1. Client 到 Resource Owner :
    • Request Credentials : 當你打開「快速日記」App並選擇使用Google帳戶登入時,App首先會引導你到Google的登入頁面。

    • Authenticate : 你將在Google的頁面上輸入你的Google帳戶憑證,即用戶名和密碼。這一步是由Google完成的,而「快速日記」App不會看到或知道你的密碼。

    • Consent : 一旦驗證成功,Google會顯示一個請求同意頁面。在這裡,Google會詢問你是否允許「快速日記」App訪問特定的Google帳戶資料。

    • Credentials : 「Resource Owner」(使用者)提供的身份資訊或某種用於辨識其身份的資料。這只是一個授權請求,而實際的身份驗證會在Resource Owner和Authorization Server之間完成。

    1. Client 到 Authorization Server
    • Authorization Request : 如果你同意上述的權限請求,「快速日記」App會從Google的授權伺服器請求一個授權碼。

    • Authorization Code : Google的授權伺服器會回傳一個短暫的授權碼給「快速日記」App。

    • Access Token : ,「快速日記」App會使用這個授權碼再次向Google的授權伺服器請求取得訪問令牌(Access Token)。

    1. Client 到 Resource Server
    • Access Token: 一旦取得訪問令牌,「快速日記」App便可以使用此令牌來存取Google雲端硬碟(或其他你同意的資料)。

    • Protected Resource: 當「快速日記」App希望保存或讀取日記時,它會使用這個Access Token向Google雲端硬碟(作為資源伺服器)提出請求,然後Google雲端硬碟會根據該令牌提供相對應的資料或服務。

更詳細的其實還有關係到Redirect部分,可以參照這篇 https://cloudsundial.com/salesforce-oauth-flows 寫得還算詳細。

如果覺得這範例太複雜,以下是一個更簡單的流程圖(LEO提供)

b. 回到Open ID Connect

上面的介紹讓我們對 OAuth 2.0 有了清晰的認識,OAuth 2.0 主要是設計來授予第三方應用程式存取特定資源的權限,而不需要分享密碼。它的核心目標是安全地授權,但它本身並不提供一個方式來傳送使用者的身份資訊。換句話說,OAuth 2.0 主要關心的是「授權」,而不是「認證」。

那麼,回到 OpenID Connect(OIDC)。它在 OAuth 2.0 的基礎上添加了一層「身份認證」的功能。這使得授權伺服器也能扮演身份提供者(Identity Provider,IDP)的角色,並提供關於使用者身份的資訊。

舉上述例子,當你使用 Google 帳戶登入「快速日記」App,這個 App 不僅獲得了存取你 Google 雲端硬碟的權限(這部分是 OAuth 2.0 負責的),還知道了你的基本身份資訊,比如名字和電子郵件(這部分就是 OIDC 負責的)。

總結一下,OAuth 2.0 負責「授權」,讓應用程式有權限執行某些操作,而 OIDC 則確定「你是誰」,提供身份認證。兩者合作,就形成了一個完整的身份驗證和授權解決方案。需要注意的是,身份認證還有其他方式,比如使用 JWT Token。

OAuth 2.0是一個授權的實作概念,IDP則是認證的實作概念

所以從我們上述OAuth2.0的圖看,授權伺服器(Authorization Server) 不僅會回傳一個「存取令牌(Access Token)」,還會附帶一些關於使用者的身份資訊。

下面有一張圖很簡單暴力,可以看到Open ID跟OAuth驗證,關鍵在回傳Authorization資料會更完整的包含身分訊息。

註:IDP只提供身分識別與認證,不包含授權喔!

c.資料格式

OICD資料由JSON格式來儲存類似的信息,在OIDC中這種JSON對象通常被稱為ID Token。內如基本上如下

  • iss(Issuer): 發行這個Token的身份提供者。
  • sub(Subject): 這個Token是關於哪個用戶的。
  • aud(Audience): 這個Token是給哪個服務提供者的。
  • exp(Expiration): Token的過期時間。
  • iat(Issued At): Token的發行時間。

範例

{ "iss": "https://accounts.google.com", "sub": "1234567890", "aud": "your-app-client-id", "exp": 1617373200, "iat": 1617369600, "email": "john.doe@example.com" // 其他屬性 }

2. SAML (Security Assertion Markup Language)

SAML,全名是"Security Assertion Markup Language",主要是用於在身份提供者(Identity Provider,簡稱IdP)和服務提供者(Service Provider,簡稱SP)之間交換認證和授權資訊的一種網路標準。但他不僅支持身份驗證,也支持豐富的授權功能。另外SAML主要焦點更傾向於身份驗證和單一登入(SSO)。通常使用HTTP POST方法來傳遞斷言(Assertion),與OIDC使用多種方法來傳遞ID令牌(ID Token),包括HTTP Header和URL參數會有點不太一樣。

這個標準包含三個主要角色:

  • Identity Provider(身分提供者) : 這個是專門負責驗證你是誰的系統。以上述例子Google來看,它就是一個IdP。

  • Service Provider(服務提供者) : 這些是你想要使用的各種線上服務,比如說郵件系統或報銷系統。

  • Agent(代理) : 這是參與認證和授權過程的軟件,通常是你的瀏覽器或其他類型的客戶端應用。

當你試著使用某個服務(SP)時,這個服務會先引導你到身份提供者(IdP)進行身份驗證。成功認證後,IdP會回傳一個證明給SP,證明你確實是誰。SP收到這份證明後,就會授予你訪問它所提供的服務的權限。

細部流程如下,

  • 一開始,User Agent(通常是使用者的瀏覽器)向Service Provider請求一個目標資源。
  • 隨後,透過一條雙向虛線,User Agent與Service Provider進行身分提供者(IDP)的探索。
  • 在確定了身分提供者之後,Service Provider會將User Agent重定向到單點登入(SSO)服務。
  • 接著,User Agent會向身分提供者(Identity Provider)請求SSO服務。
  • 之後,透過一條雙虛線,User Agent與Identity Provider進行使用者的身分認證。
  • 身分認證完成後,Identity Provider會回應User Agent一個包含XML格式的表單。
  • User Agent接收到這個表單後,會向Service Provider的斷言消費服務(Assertion Consumer Service)進行請求。
  • Service Provider在處理完這次的請求後,會向User Agent發出一條重定向到目標資源的指令。
  • 隨後,User Agent會再次向Service Provider請求該目標資源。
  • 最後,Service Provider會回應User Agent,提供他們所請求的資源。

以我們OAuth2.0的「快速日記」App為例子,Service Provider (SP)為「快速日記」App,Identity Provider (IdP)為Google,User Agent就是你所使用的裝置(例如手機、電腦等)上的瀏覽器或「快速日記」App應用程式。另外,Google雲端硬碟(Google Drive)部分也會算是 Service Provider這一區塊。

最後這邊稍微提一下,流程有一個步驟是回傳XHTML,在SSO(單一登入)的流程中,當身份提供者(Identity Provider)需要讓使用者完成某些操作,例如輸入帳號密碼或選擇身份認證方式時,它會傳回一個XHTML頁面給User Agent(通常是瀏覽器)來顯示。舉個例子,想像你嘗試使用Google帳戶登入一個App。當你點擊"使用Google登入"後,如果你尚未在Google登入或Google需要確認你的身份,你的瀏覽器會被重導向至Google的登入頁面。這個登入頁面就是一個由Google傳回的XHTML內容。

簡單來說,XHTML的回傳就是在說:「這裡有一個網頁內容,請瀏覽器將其顯示給使用者。」在你提到的流程中,當身份提供者回傳XHTML給User Agent,就是讓瀏覽器展示某些內容或請求使用者完成某些操作,如登入或選擇認證方式。

a. 資料格式

SAML中,數據通常會以一個XML文件的形式出現,這個文件被稱為「斷言」(Assertion)。斷言中會包含多種元素,例如:

  • Issuer(發行者): 這個斷言是由哪個身份提供者(IdP)發出的。
  • mSubject(主題): 這個斷言是關於哪個用戶的。
  • Conditions(條件): 斷言在什麼情況下有效,例如有效期限。
  • AttributeStatement(屬性聲明): 包含用戶的一些屬性,比如用戶名、郵箱等。

範例

<Assertion> <Issuer>https://idp.example.com</Issuer> <Subject>john.doe</Subject> <Conditions> <!-- 條件,比如有效時間 --> </Conditions> <AttributeStatement> <Attribute Name="email">john.doe@example.com</Attribute> <!-- 其他屬性 --> </AttributeStatement> </Assertion>

3. OIDC vs SAML

最後比較整理一下這兩者不同

  • 設計考量
    • SAML : 相對老的標準,主要在企業環境和內部系統中使用。它是一個非常完整的解決方案,不僅支持身份驗證,也支持豐富的授權功能。
    • OIDC : 這是一個相對新的標準,基於OAuth 2.0,主要用於消費者級的應用。它相對簡單,並且更注重身份驗證。
  • 數據格式
    • SAML : 使用XML作為數據格式。
    • OIDC : 使用JSON作為數據格式。
  • 傳輸方法
    • SAML : 通常使用HTTP POST方法來傳遞斷言(Assertion)。
    • OIDC : 可以使用多種方法來傳遞ID令牌(ID Token),包括HTTP Header和URL參數。
  • 應用場景
    • SAML : 通常用在企業內部的各種系統間,如你在工作中可能會遇到的那種。
    • OIDC : 更常見於互聯網上的消費者服務,比如你用Google帳號登入其他網站。

4. IDP

在我們討論OIDC(OpenID Connect)和SAML(安全斷言標記語言)的過程中,Identity Provider(IDP)扮演著關鍵角色。IDP負責驗證使用者身份,存儲和管理使用者的認證資料,如用戶名和密碼。一旦使用者成功通過認證,IDP會生成一份斷言(例如,SAML斷言)。這份斷言不僅包括使用者的基本身份資訊,還可能包含其他特定屬性。由於這份斷言是加密和簽名的,服務提供者(Service Provider, SP)可以驗證其真實性。透過IDP,使用者可以單一登入(SSO)以訪問多個相關服務或應用程式。

讓我們簡單看一下IDP如何進行身份管理:

  • 資料庫存儲:IDP會有一個專門的資料庫,用於儲存使用者的各種身份資訊,例如帳號、密碼和電子郵件等。
  • 註冊過程:當使用者首次註冊某個服務,他們會在IDP中提交必要的身份資訊。
  • 認證:當使用者嘗試登入某個服務時,IDP會檢查提供的資料與資料庫中存儲的信息是否一致。
  • 多重認證:為了提高安全性,IDP可能會使用多重認證,例如:短信驗證碼、指紋或臉部識別等。
  • 更新與撤銷:使用者可以隨時更新或修改他們在IDP中的身份資訊。若發現帳戶有被不當存取的風險,IDP會暫停或永久撤回該帳戶的訪問權限。

於斷言或令牌中,一般會包含以下幾項信息:

  • 主體 (Subject):這是使用者的唯一標識,如用戶名或電子郵件。
  • 發行者 (Issuer):該令牌是由哪個IDP發出的。
  • 有效期 (Expiration):令牌的有效時間,過了這個時間,令牌就會過期。
  • 其他屬性:例如,使用者的姓名、角色、權限等。
  • 簽名 (Signature):為了確保令牌的完整性和來源,IDP會使用其私鑰簽署令牌。接收令牌的服務提供者(SP)可以使用IDP的公開鑰匙來驗證此簽名。

例如,當使用Keycloak作為IDP時,它會發行一個格式為JWT(JSON Web Token)的令牌作為身份證明。

{ "header": { "alg": "RS256", "typ": "JWT", "kid": "dEaD-bEEF-CafE" }, "payload": { "iss": "https://keycloak.example.com/auth/realms/myrealm", // 發行者 "sub": "12345678-1234-1234-1234-1234567890ab", // 主體 (使用者ID) "aud": "quick-diary-app", // 受眾 (意味著這個令牌是為了"quick-diary-app"而生成的) "exp": 1618828800, // 有效期 (Unix時間戳表示的過期時間) "iat": 1618825200, // 令牌的發行時間 "auth_time": 1618825189, // 使用者最後一次認證的時間 "name": "Spyua Chen", // 使用者的全名 "given_name": "Spyua", // 使用者的名字 "family_name": "Chen", // 使用者的姓氏 "email": "spyua@example.com", // 使用者的電子郵件地址 "preferred_username": "spyua" // 使用者選擇的用戶名 }, "signature": "ABCDEF...XYZ" // 簽名部分 }