OAuth 2.0 授權框架

之前在討論 API 身分驗證時,已有小提一下 OAuth 2.0 授權框架(以下簡稱 OAuth2)的概觀了。

授權與存取控制

在開始講細節之前,先簡單說明一下身分驗證(authentication)、授權(authorization)與存取控制(access control)的差異,有些人很容易把這三者搞混。

存取控制如 ACL(access control list)RBAC(role-based access control)

身分驗證

透過身分驗證,可以讓系統知道目前的使用者是哪個實體。

如:輸入 root 帳號密碼成功,可以知道現在進來的使用者,是 Linux 裡所定義的超級使用者(super user)。

授權

在 OAuth2 的世界裡,授權指的是使用者,讓第三方應用程式取得使用者的資源。

如:使用者的大頭照放在 Facebook,而某個第三方軟體如 iT 邦幫忙,想取得使用者的大頭照,必須要經過使用者授權。注意:要或不要的決定權在於使用者。

存取控制

系統管理者,或被授權的使用者,才有權利更改存取控制的策略。目的是管理並控制使用者存取資源的權限。

如:留言板系統,前台使用者只能留言,後台使用者可以刪除留言。再一次與授權比較如下:

  • 存取控制:管理者控制使用者可存取哪些資源
  • 授權:使用者可控制第三方應用程式能存取哪些資源

OAuth 2.0 的授權流程

首先要了解 OAuth2 所定義的角色:

  • resource owner - 資源擁有者,即「使用者」
  • resource server - 資源伺服器,用來存放使用者受保護資源的伺服器
  • client - 第三方應用程式,是對資源擁有者的資源有興趣的服務
  • authorization server - 授權伺服器,專門用來處理授權的伺服器

而這四個角色之間的互動如下:

下圖源自 RFC 6749 1.2

@startuml
Client -> ResourceOwner: (1) Authorization Request
Client <- ResourceOwner: (2) Authorization Grant
Client -> AuthorizationServer: (3) Authorization Grant
Client <- AuthorizationServer: (4) Access Token
Client -> ResourceServer: (5) Access Token
Client <- ResourceServer: (6) Protected Resource
@enduml

以「iT 邦幫忙,想取得使用者在 Facebook 的大頭照」為例:

  1. iT 邦幫忙請求使用者的授權。可以直接發出授權請求,或是透過 Facebook 做為中介
  2. iT 邦幫忙收到同意授權的憑據,此憑據是由 OAuth2 裡所定義的四種流程的其中一種來傳送給 iT 邦幫忙
  3. iT 邦幫忙使用憑證向 Facebook 要求 access token
  4. Facebook 驗證 iT 邦幫忙的身分,並確認同意授權的憑據有效,即可發 access token
  5. iT 邦幫忙使用 access token 向 Facebook 請求資源
  6. Facebook 確認 access token 無誤,即可回傳資源給 iT 邦幫忙

從上面這個流程可以發現,除了第二步不明確之外,其他流程都很清楚:要求授權,使用者同意即可拿到 access token,接著就可以拿到想要拿的資源。

OAuth 2.0 Grant Type

OAuth2 是一個設計很靈活的框架,不但預定義了四種授權類型,同時也保留了彈性可以自定義類型,如 RFC 7521 - Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants 是利用 Assertion(如 SAML AssertionJWT)來換取 access token 的框架。

預定義的授權類型如下:

  • Authorization code grant
  • Implicit grant
  • Resource owner password credentials grant
  • Client credentials grant

其中 client credentials grant 類似之前 API 身分驗證所提到的信任服務機制,屬於服務與服務之間的串接,而不經由使用者。

@startuml
Client --> AuthorizationServer: Client Authentication
Client <-- AuthorizationServer: Access Token
@enduml

其他三種授權類型都會經由使用者,其中最簡單,同時也被定義為最後無路可走才能用的方法為 resource owner password credentials grant,簡單來說,它是使用者將帳號密碼直接提供給第三方應用程式,而第三方應用程式再拿來向授權伺服器要求 access token。

@startuml
ResourceOwner -> Client: Resource Owner Password Credentials
Client --> AuthorizationServer: Resource Owner Password Credentials
Client <-- AuthorizationServer: Access Token
@enduml

Resource owner password credentials grant 只能用在授權伺服器對第三方應用程式有足夠的信任(如,公司內部服務串接),不然像 Facebook 帳號密碼提供給第三方應用程式處理,其實是非常不安全的。

Implicit grant 可以用於如 SPA 或 App 等,沒有後端服務的場景。

@startuml
UserAgent -> AuthorizationServer: Authorization Request
UserAgent <- AuthorizationServer: Authorization Grant
UserAgent -> AuthorizationServer: Resource Owner Authenticates
UserAgent <- AuthorizationServer: Redirection URI with Access Token in Fragment
UserAgent -> ResourceServer: Request Resource
@enduml

從圖可以了解,access token 最終會存放在 UserAgent 裡,這其實不是很安全的方法,只要 UserAgent 有漏洞,token 就有可能外流。

一般最常見,也相較安全的方法還是使用 authorization code grant 較多。明天將會對此流程做比較詳細的說明。

參考資料