理解OIDC協議和認證機制

微笑刺客D發表於2022-03-31

當網際網路應用越來越多,每個應用程式都實現了自己的身份儲存、認證和授權,使用者需要在應用上反覆的註冊與登入,體驗糟糕,使用者身份資訊無法在多個應用間共享與同步。當使用企業應用時,企業提供了一系列應用,儘管是同一使用者操作,但還是不得不切換註冊與登入。

是否可以有那麼一種方式,我在某個代理網站註冊一個賬號,如果登入其他網站時,其他網站可以到代理網站去獲取資訊。只要代理網站足夠富有生命力,那麼總是可以省略很多乏味的註冊登入流程。

這些想法在技術的發展過程中出現了,如WS-Federation、SAML2.0、OpenID、OAuth、OIDC...

OpenID&OAuth發展歷史

圖片

還有一些修訂和擴充套件,此處就不體現了,主要是想聚焦於OpenID和OAuth是不一樣的。

  • OpenID是面向身份認證,對使用者身份進行認證判斷是否有效。
  • OAuth是面向授權過程,在已知當前使用者身份合法後,控制使用者能夠訪問的資源,考慮保護被訪問的資源。

OpenID

OpenID是一個去中心化的網上身份認證系統。對於支援OpenID的網站,使用者不需要記住像使用者名稱和密碼這樣的傳統認證標記。取而代之的是,他們只需要預先在一個作為OpenID身份提供者(identity provider, IdP)的網站上註冊。OpenID是去中心化的,任何網站都可以使用OpenID來作為使用者登入的一種方式,任何網站也都可以作為OpenID身份提供者。OpenID既解決了註冊問題而又不需要依賴於中心性的網站來確認數字身份。

OpenID給使用者提供一個統一網路身份,遵守OpenID網路身份,遵守OpenID協議的應用網站(在OpenId術語裡叫Relying Parties,即RP)需要使用者登入時,引導使用者到第三方OpenID身份提供方(OpenId術語裡叫OpenID identity provider,即OP)去認證,認證通過即登入成功。這樣就省去了每個應用網站註冊、登入的煩惱與乏味。解決了最開始提到的一個問題,各應用需要獨立完成註冊與登入流程,需要實現與維護獨立的使用者資料庫。

OAuth

OAuth是一個授權協議,解決的是應用可以訪問使用者在另一應用上的某些授權資源,但此應用不需要知道使用者在另一應用上的賬戶密碼,即無需向另一應用透露使用者的憑據便可以訪問另一應用上受控的資源。

  • 2006年11月,當時布萊恩·庫克正在開發Twitter的OpenID實現。與此同時,社交書籤網站Ma.gnolia需要一個解決方案允許使用OpenID的成員授權Dashboard訪問他們的服務。這樣庫克、克里斯·梅西納和來自Ma.gnolia的拉里·哈爾夫(Larry Halff)與戴維·雷科爾頓會面討論在Twitter和Ma.gnolia API上使用OpenID進行委託授權。但他們討論得出結論,認為OpenID沒有完成API訪問委託的開放標準。
  • 2007年4月,成立了OAuth討論組,這個由實現者組成的小組撰寫了一個開放協議的提議草案。來自Google的德維特·克林頓獲悉OAuth專案後,表示他有興趣支援這個工作。
  • 2007年7月,團隊起草了最初的規範。隨後,Eran Hammer-Lahav加入團隊並協調了許多OAuth的稿件,建立了更為正式的規範。
  • 2007年10月,OAuth Core 1.0最後的草案發布了。
  • 2008年11月,在明尼阿波利斯舉行的網際網路工程任務組第73次會議上,舉行了OAuth的BoF討論將該協議納入IETF做進一步的規範化工作。這個會議參加的人很多,關於正式地授權在IETF設立一個OAuth工作組這一議題得到了廣泛的支援。
  • 2010年4月,OAuth 1.0協議發表為RFC 5849,一個非正式RFC。
  • 2012年10月,OAuth 2.0釋出,正式發表為RFC 6749。OAuth 2.0是OAuth協議的下一版本,但不向下相容OAuth 1.0。OAuth 2.0關注客戶端開發者的簡易性,同時為Web應用、桌面應用、手機和智慧裝置提供專門的認證流程。

Open ID Connect

OpenID團隊本來希望使用者使用OpenID來進行身份認證, 但因為授權過程包括認證過程作為一部分,所以授權意味著經過了認證這一過程。由此,一些使用者選擇了OAuth身份認證的簡易性,並且由於“管理使用者憑據的任務可以委託給外部服務”以及“因為新使用者註冊過程可以省略,使用該服務的障礙變得更低”等優點而迅速佔據主導地位,使用OAuth2.0作為身份認證的趨勢變得流行。

OpenID團隊不得不承認使用者更喜歡OAuth2.0,因此,他們在OAuth之上定義了一個新的身份認證規範OpenID Connect(OIDC),這個規範基於OAuth2.0進行了小幅擴充套件,在OAuth2.0上構建了身份層,使其可用作身份認證協議。

圖片

即OpenID Connect (OIDC) 是基於 OAuth 2.0 構建的身份認證協議。

OpenID+OAuth 2.0=OpenID Connect


OIDC主要術語

  • Claim: 宣告資訊,簡要格式展示(如身份證上格式)。
  • Claims Provider: 宣告資訊提供方(如OAuth2.0中的Authorization Server能夠返回Id token,其中攜帶著宣告資訊)。
  • End-User(EU): 人類參與者(完成認證活動的人)。
  • ID Token: 包含EU身份資訊的宣告(Claim),以JWT(Json Web Token)格式進行儲存傳遞。JWT具有自包含性、緊湊性和防篡改機制等特點。使得ID Token可以安全的傳遞給第三方應用並且容易被驗證。
  • OpenID Provider (OP): 提供身份認證的服務方,OAuth2.0中的Authorization Server(授權伺服器),用來提供身份認證服務以及返回Claim資訊給第三方應用(Relying Party)。
  • Relying Party (RP):受信任的第三方應用(OAuth2.0中的Client),需要EU完成鑑權,並從OP處獲得Claim資訊的應用。
  • UserInfo Endpoint:使用者資訊的介面,當RP使用Access token請求該介面時,能夠返回當前使用者的身份資訊。
    圖片

OIDC協議簇

OIDC由一系列規範文件組成,包括一個核心文件和多個可選支援的文件來提供擴充套件支援:

  • Core:必選。定義了OIDC核心的功能,在OAuth 2.0之上構建身份認證,以及使用宣告(如身份證上的簡要描述)方式來傳遞使用者的資訊。
  • Discovery:可選。定義了第三方應用如何動態發現OIDC服務提供方後設資料文件(比如提供的服務地址,採用的加密方法,支援的授權型別等等)。
  • Dynamic Registration:可選。定義了第三方應用如何註冊到OIDC身份提供方。
  • OAuth 2.0 Multiple Response Types:定義了幾種新的為OAuth2.0響應方式(原來常見的授權碼code、隱式授權token基礎上增加了id_token以及混合code、token和id_token的方式)。
  • OAuth 2.0 Form Post Response Mode:可選。在OAuth2.0的響應引數上擴充套件了OIDC所需的引數。提供了基於form表單響應資訊的模式,使用post請求型別傳給第三方應用,響應引數以application/x-www-form-urlencoded格式儲存body中。
  • RP-Initiated Logout: 可選。定義了第三方應用如何登出當前登入使用者的機制。
  • Session Management:可選。定義瞭如何管理OIDC上已登入使用者的會話資料,以便當OP上的使用者登出時,也能夠方便在RP上登出。
  • Front-Channel Logout:可選。基於前端的登出機制,使得第三方應用不需要嵌入認證服務方的iframe來登出。
  • Back-Channel Logout:可選。基於後端的登出機制,定義了RP和OP直接如何通訊來完成登出。
  • OpenID Connect Federation: 可選。定義瞭如何在OP和RP間建立可靠的信任的機制。
  • Initiating User Registration via OpenID Connect: 可選。提供一種方式允許在RP指示下,能夠在OP上註冊使用者的機制。
    如下圖所示,上部分描述OIDC的協議簇,以及其中最為核心的Core規範。下部分是作為支撐OIDC的其他協議規範。

圖片

對於這些協議來講,可能看著就難受,簡要了解個概念即可,實際開發時這些都會逐漸浮出水面。


OIDC&OpenID2.0差異

  • OpenID Connect執行許多與OpenID 2.0相同的任務,但是API更友好且可使用在原生應用和移動應用。
  • OpenID Connect 定義了用於可靠簽名和加密的可選機制。
  • OAuth 1.0a和OpenID 2.0的整合需要擴充套件,而OIDC本身整合了OAuth2.0。

OIDC&OAuth2.0差異

OIDC仍然使用OAuth中的授權伺服器將使用者身份認證資訊以Id token的方式給到第三方應用,第三方應用可以驗證使用者標識並從中獲取使用者的基本資訊以及通過OAuth2.0的授權流程訪問使用者的詳細資訊。如下圖所示,對於使用者認證部分採用認證協議如WS-Fed、OIDC等,對於資源的訪問控制以OAuth2.0協議為主。

圖片

OIDC中的Id token和OAuth2.0中核心的Access token各自效力或是關注的部分不同。

  • OAuth2提供了Access Token來解決授權第三方應用訪問受保護資源的問題;
  • OIDC遵循OAuth2.0協議流程在這個基礎上提供了ID Token來解決第三方應用標識使用者身份的問題。
    圖片

OIDC抽象流程

OIDC的流程主要由以下5個步驟構成:

  1. 第三方應用(RP)傳送認證請求到認證服務方(OP)
  2. 使用者在認證頁面進行認證與選擇授權內容
  3. 認證服務方(OP)對認證請求進行驗證,傳送Id token及Access token給第三方應用(RP)
  4. 第三方應用可使用Access token請求使用者資訊或其他授權內的資源
  5. 資源服務對Access token校驗並返回使用者資訊或資源
    圖片

流程上,在OAuth2.0中授權碼模式和隱式授權模式下,OIDC和OAuth2.0是一樣的,但有幾個授權模式在某些情況下,在OIDC中就不存在了,當使用者無需經過身份認證過程即可獲得Access token,比如如下兩種模式。

  • 資源所有者密碼憑證授權(Resource Owner Password Credentials Grant):第三方應用能夠獲取到使用者的登入憑證就直接可以向授權伺服器請求Access token,如此,就去掉了標識使用者身份這一過程了。
  • 客戶端憑證授權(Client Credentials Grant):這種是標識客戶端,直接的參與者人都沒有加入到流程中,也不存在標識使用者是誰了。

OIDC的幾種認證方式

OIDC的認證流程主要是由OAuth2的幾種授權流程延伸而來的,主要有以下3種:

  • 授權碼流程(Authorization Code Flow):基於OAuth2的授權碼流程,在原來code換取Access token的基礎上增加了一個Id token。
  • 隱式流程(Implicit Flow):基於OAuth2的隱式流程,在原來從授權伺服器重定向到第三方應用僅返回Access token的基礎上增加了一個Id token。
  • 混合流程(Hybrid Flow):混合了授權碼流程(Authorization Code Flow)和隱式流程(Implici Flow),能夠按照引數配置的不同,控制Id token的返回位置與Access token的有無。
    注意:如上省略了Refresh token,關注於Id token和Access token。

授權碼流程

1、第三方應用通過瀏覽器重定向到授權伺服器(OP)的認證頁面來進行使用者認證與執行授權流程。重定向時使用的引數是基於OAuth2.0中的大部分引數。主要如下幾個

  • scope:必選。選擇的授權範圍,當是OIDC請求時,需要包含openid選項,如下示例所示。
  • response_type:必選。響應型別方式,使用授權碼流程時,為code.
  • client_id:必選。第三方應用提前在授權伺服器處註冊得到的id值。
  • redirect_uri:必選。重定向到OP認證授權完畢後重定向到RP的地址。
  • state:推薦。第三方應用(RP)提供的一個字串,授權伺服器(OP)會原樣返回給第三方應用(RP),以阻止CSRF攻擊。
    如上幾個是常使用到的授權碼流程中所需的引數,實際上還有許多其他引數可以依照不同場景的需要使用上。其他引數資訊https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest

圖片

2、當使用者完成認證資訊填寫與執行授權操作後,授權伺服器(OP)對使用者認證資訊的稽核和授權範圍的校驗。有效後重定向到第三方應用(RP)指定的回撥地址(第1步中的redirect_uri),將code和state引數作為查詢引數附加在回撥地址後。

圖片
3、第三方應用(RP)通過code來請求認證服務方的Token EndPoint換取Token。

圖片

然後Token EndPoint會返回響應的Token,其中除了OAuth2規定的部分資料外,還會附加一個id_token的欄位。

{
    "access_token": "SlAV32hkKG",
    "token_type": "Bearer",
    "refresh_token": "8xLOxBtZp8",
    "expires_in": 3600,
    "id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}

4、請求使用者資訊或授權內的資源。
圖片


隱式流程

在OAuth2.0中,隱式授權使用的response_type是token,而在OIDC中,變為了id_token token或是僅id_token,當僅使用id_token時,則不會返回Access token了。其餘引數則和OAuth2.0中的隱式授權一致。但OIDC中相比OAuth2.0隱式流程額外增加了一個引數nonce

  • nonce:必填。字串值,用於將第三方應用的會話與 Id token關聯,並緩解重放攻擊。該值未經修改地從身份驗證請求傳遞到 Id token中。為了防止攻擊者猜中值,隨機數值中必須存在足夠的熵。

注意:隱式流程中OAuth2.0的state和OIDC的nonce區別

https://stackoverflow.com/questions/46844285/difference-between-oauth-2-0-state-and-openid-nonce-parameter-why-state-cou

1、第三方應用(RP)攜帶引數跳轉到授權伺服器(OP)的認證授權頁面,等待使用者認證與執行授權。

圖片

2、當授權伺服器(OP)完成對使用者認證資訊的稽核和授權範圍的校驗,重定向回第三方應用(RP)並按照請求時的response_type返回id token、access token(當僅設定id_token時不返回)。注意url的hash部分(#後面)。

圖片

3、後續便是請求使用者資訊或是授權內的資源。


混合流程

這種是將授權碼和隱式流程結合起來,一部分token來源於授權伺服器(OP)重定向到第三方應用(RP)時帶過來,一部分來源於第三方應用(RP)向授權伺服器(OP)發起請求而得到。這種流程中,response_type,可以混合著用,如code id_token,code token或是code id_token token。

1、第三方應用(RP)向授權伺服器(OP)發起認證請求。此處使用授權碼和隱式中僅id_token的組合。

圖片

2、當授權伺服器(OP)完成對使用者認證資訊的稽核和授權範圍的校驗,重定向回第三方應用(RP)並按照請求時的response_type返回id token、access token(當僅設定id_token時不返回)。

  • access_token:當response_type中有token選項時,則會返回access_token
  • id_token:當response_type中有id_token選項時,則會返回id_token
  • code:混合流程中,這個是必選的,所以總是會返回code。
    圖片

3、第三方應用(RP)通過code來請求授權伺服器(OP)換取Token。這和授權碼流程一致了。


Id token格式

認證服務返回的ID Token需要嚴格遵守JWT(JSON Web Token)的定義,下面是JWT(JSON Web Token)的定義細節:

  • iss=Issuer Identifier: 必須。認證服務的唯一標識,一個區分大小寫的https URL,不包含query和fragment元件。
  • sub=Subject Identifier:必須。iss提供的終端使用者的標識,在iss範圍內唯一,最長為255個ASCII個字元,區分大小寫。
  • aud=Audience(s):必須。標識ID Token的受眾,必須包含OAuth2的client_id,分大小寫的字串陣列。
  • exp=Expiration time:必須。超過此時間的ID Token會作廢。
  • iat=Issued At Time:必須。JWT的構建的時間。
  • auth_time=AuthenticationTime:終端使用者完成認證的時間。
  • nonce:傳送認證請求的時候提供的隨機字串,用來減緩重放攻擊,也可以用來關聯客戶端Session。如果nonce存在,第三方應用必須驗證nonce。
  • acr=Authentication Context Class Reference:可選。表示一個認證上下文引用值,可以用來標識認證上下文類。
  • amr=Authentication Methods References:可選。表示一組認證方法。
  • azpAuthorized party:可選。結合aud使用。只有在被認證的一方和受眾(aud)不一致時才使用此值,一般情況下很少使用。
    如下是一個典型ID Token的示例:
{
    "exp": 1614187991,
    "iss": "https://authorization-server.com/oauth",
    "sub": "a0903223-a120-91e0-c342-10bd237c24c1",
    "aud": "client1",
    "iat": 1614151991,
    "auth_time": 0,
    "nonce": "n-0S6_WzA2Mj",
    "acr": "1",
    "azp": "client1",
    "nbf": 0,
    "typ": "ID",
    "session_state": "150df80e-92a1-4b0c-a5c5-8c858eb5a848",
    "userId": "123456",
    "preferred_username": "testera",
    "given_name": "tester",
    "family_name": "a",
    "email": "testera@myweb.com"
}

關於ID Token的更詳細的定義請參見OpenID Connect Core 1.0


參考

https://openid.net/connect/

https://www.jianshu.com/p/2c602974bc98

https://baike.baidu.com/item/OpenID?wtp=tt

http://www.imooc.com/article/4167

https://www.cnblogs.com/linianhui/p/openid-connect-core.html

2022-03-31,望技術有成後能回來看見自己的腳步

相關文章