基于OAuth2的OIDC (OpenId Connect) 身份認證

OIDC協(xié)議

OIDC(OpenID Connect)是在OAuth2上構建了一個身份層,是一個基于OAuth2協(xié)議的身份認證標準協(xié)議。

OAuth2協(xié)議

OAuth2是一個授權協(xié)議,它無法提供完善的身份認證功能【1】,OIDC使用OAuth2的授權服務器來為第三方客戶端提供用戶的身份認證,并把對應的身份認證信息傳遞給客戶端。

使用OAuth2進行認證的常見誤區(qū)

如果用OAuth2進行認證,會有許多問題。

  • 在OAuth2中,token被設計成是對客戶端不透明的,但在用戶身份認證的上下文環(huán)境中, 客戶端往往需要能夠從token中派生一些信息。這可以通過定義一個雙重目的(dual-purposing)的客戶端以解析和理解的token來完成。但是OAuth2協(xié)議并沒有為access token本身定義特定的格式貨結構,因此需要在OAuth2協(xié)議的基礎上,利用諸如OpenId Connect的ID Token在響應中提供一個次要的標記,它將和access token一起發(fā)送給客戶端中。一方面,保持了token是對客戶端的不透明,另一方面,為客戶端提供了其所需的認證信息。
  • OAuth保護的是資源,獲取用戶屬性的API(identity API)通常沒有辦法告訴你用戶是否存在。而且,在某些情況下,用戶無需身份驗證即可獲得access token(比如[認證授權] 1.OAuth2授權 - 5.4 Client Credentials Grant)。也就是說Access Token并不能和某個用戶關聯(lián)起來。
  • 在某些場合,例如,使用implicit流程(這個流程中直接把acces token作為url的hash參數(shù)([認證授權] 1.OAuth2 授權 - 5.2.2 Access Token Response))中,User Agent可以獲得token,也就你開辟了一個注入 access token到應用程序外部(并可能在應用程序外部泄露)的地方。如果Client不通過某種機制驗證access token,則它無法區(qū)分access token是有效的令牌還是攻擊的令牌。
  • 很可能有一個幼稚的(naive)客戶端,從其他的客戶端拿到一個有效的token來作為自己的登錄事件。畢竟token是有效的,對API的訪問也會返回有效的用戶信息。問題在于沒有用戶做任何事情來證明用戶存在,在這種情況下,用戶甚至都沒有授權給幼稚的(naive)客戶端。
  • 如果攻擊者能夠攔截或者替換來自Client的一個調用,它可能會改變返回的用戶信息,而客戶端卻無法感知這一情況。這將允許攻擊者通過簡單地在正確的調用序列中交換用戶標識符來模擬一個幼稚的(naive)Client上的用戶。
  • 基于OAuth 身份(identity)API的最大問題在于,即使使用完全符合OAuth的機制,不同的提供程序不可避免的會使用不同的方式實現(xiàn)身份(identity)API。

OIDC核心概念:ID Token

OAuth2提供了Access Token來解決授權第三方客戶端訪問受保護資源的問題;OIDC在這個基礎上提供了ID Token來解決第三方客戶端標識用戶身份認證的問題。OIDC的核心在于在OAuth2的授權流程中,一并提供用戶的身份認證信息(ID Token)給到第三方客戶端,ID Token使用JWT格式來包裝。此外還提供了UserInfo的接口,用戶獲取用戶的更完整的信息。

參與角色

主要的術語以及概念介紹:

  • EU:End User:一個人類用戶。
  • RP:Relying Party ,用來代指OAuth2中的受信任的客戶端,身份認證和授權信息的消費方;
  • OP:OpenID Provider,有能力提供EU認證的服務(比如OAuth2中的授權服務),用來為RP提供EU的身份認證信息;
  • ID Token:JWT格式的數(shù)據(jù),包含EU身份認證的信息。
  • UserInfo Endpoint:用戶信息接口(受OAuth2保護),當RP使用Access Token訪問時,返回授權用戶的信息,此接口必須使用HTTPS。

工作流程

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

  1. RP發(fā)送一個認證請求給OP
  2. OPEU進行身份認證,然后提供授權;
  3. OPID TokenAccess Token(需要的話)返回給RP;
  4. RP使用Access Token發(fā)送一個請求UserInfo EndPoint;
  5. UserInfo EndPoint返回EUClaims。
    oidc.jpg

    注意這里面RP發(fā)往OP的請求,是屬于Authentication類型的請求,雖然在OIDC中是復用OAuth2的Authorization請求通道,但是用途是不一樣的,且OIDC的AuthN請求中scope參數(shù)必須要有一個值為的openid的參數(shù),用來區(qū)分這是一個OIDC的Authentication請求,而不是OAuth2的Authorization請求。

什么是ID Token

OIDC對OAuth2最主要的擴展就是提供了ID TokenID Token是一個安全令牌,是一個授權服務器提供的包含用戶信息(由一組Cliams構成以及其他輔助的Cliams)的JWT格式的數(shù)據(jù)結構。
另外ID Token必須使用JWS進行簽名和JWE加密,從而提供認證的完整性、不可否認性以及可選的保密性。一個ID Token的例子如下:

 1 {
 2    "iss": "https://server.example.com",
 3    "sub": "24400320",
 4    "aud": "s6BhdRkqt3",
 5    "nonce": "n-0S6_WzA2Mj",
 6    "exp": 1311281970,
 7    "iat": 1311280970,
 8    "auth_time": 1311280969,
 9    "acr": "urn:mace:incommon:iap:silver"
10   }

如何獲取ID Token

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

  1. Authorization Code Flow:使用OAuth2的授權碼來換取Id TokenAccess Token。
  2. Implicit Flow:使用OAuth2的Implicit流程獲取Id TokenAccess Token。
  3. Hybrid Flow:混合Authorization Code Flow+Implici Flow。

Resource Owner Password Credentials Grant是需要用途提供賬號密碼給RP的,賬號密碼給到RP了,就不再需要ID Token了。

Client Credentials Grant這種方式根本就不需要用戶參與,更談不上用戶身份認證了。這也能反映授權和認證的差異,以及只使用OAuth2來做身份認證的事情是遠遠不夠的,也是不合適的。

這里主要介紹基于Authorization Code的認證請求/答復。

基于Authorization Code的認證請求的請求

所有的Token都是通過Token EndPoint來發(fā)放的。構建一個OIDC的Authentication Request需要提供如下的參數(shù):

  • scope:必須。OIDC的請求必須包含值為openid的scope的參數(shù)。
  • response_type:必選。同OAuth2。
  • client_id:必選。同OAuth2。
  • redirect_uri:必選。同OAuth2。
  • state:推薦。同OAuth2。防止CSRF, XSRF。

以上這5個參數(shù)是和OAuth2相同的。除此之外,還定義了一些參數(shù)【2】例如:

  • response_mode:可選。OIDC新定義的參數(shù),用來指定Authorization Endpoint以何種方式返回數(shù)據(jù)。

一個簡單的示例如下:

GET /authorize?
    response_type=code
    &scope=openid%20profile%20email
    &client_id=s6BhdRkqt3
    &state=af0ifjsldkj
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
  Host: server.example.com
基于Authorization Code的認證請求的響應

授權服務器接收到認證請求之后,需要對請求參數(shù)做嚴格的驗證。驗證通過后引導EU進行身份認證并且同意授權。在這一切都完成后,會重定向到RP指定的回調地址,并且把codestate參數(shù)傳遞過去。比如:

  HTTP/1.1 302 Found
  Location: https://client.example.org/cb?
    code=SplxlOBeZQQYbYS6WxSbIA
    &state=af0ifjsldkj
獲取ID Token

RP使用上一步獲得的code來請求Token EndPoint,這一步同OAuth2。然后Token EndPoint會返回響應的Token,其中除了OAuth2規(guī)定的部分數(shù)據(jù)外,還會附加一個id_token的字段。id_token字段就是上面提到的ID Token。例如:

  HTTP/1.1 200 OK
  Content-Type: application/json
  Cache-Control: no-store
  Pragma: no-cache

  {
   "access_token": "SlAV32hkKG",
   "token_type": "Bearer",
   "refresh_token": "8xLOxBtZp8",
   "expires_in": 3600,
   "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
     yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
     NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
     fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
     AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
     Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
     NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
     QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
     K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
     XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
  }

其中看起來一堆亂碼的部分就是JWT格式的ID Token。在RP拿到這些信息之后,需要對id_token以及access_token進行驗證。至此,可以說用戶身份認證就可以完成了,后續(xù)可以根據(jù)UserInfo EndPoint獲取更完整的信息。

OIDC協(xié)議簇

除了Core核心規(guī)范內容多一點之外,另外7個都是很簡單且簡短的規(guī)范,另外Core是基于OAuth2的,也就是說其中很多東西在復用OAuth2。


oicd_p_s.png

OpenId Connect定義了一個發(fā)現(xiàn)協(xié)議,它允許Client輕松的獲取有關如何和特定的身份認證提供者進行交互的信息。在另一方面,還定義了一個Client注冊協(xié)議,允許Client引入新的身份提供程序(identity providers)。通過這兩種機制和一個通用的身份API,OpenId Connect可以運行在互聯(lián)網(wǎng)規(guī)模上運行良好,在那里沒有任何一方事先知道對方的存在。

UserInfo Endpoint

UserIndo EndPoint是一個受OAuth2保護的資源。在RP得到Access Token后可以請求此資源,然后獲得一組EU相關的Claims,這些信息可以說是ID Token的擴展,

  GET /userinfo HTTP/1.1
  Host: server.example.com
  Authorization: Bearer SlAV32hkKG

成功之后相應如下:

  HTTP/1.1 200 OK
  Content-Type: application/json

  {
   "sub": "248289761001",
   "name": "Jane Doe",
   "given_name": "Jane",
   "family_name": "Doe",
   "preferred_username": "j.doe",
   "email": "janedoe@example.com",
   "picture": "http://example.com/janedoe/me.jpg"
  }

【1】OAuth2中的access_token
【2】[認證 & 授權] 4. OIDC(OpenId Connect)身份認證(核心部分)

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容