OAuth 2.0 / RCF6749 協議解讀

  OAuth是第三方應用授權(Authorization)的開放標準,目前最新版本是2.0,以下將要介紹的內容和概念主要來源於該版本。 恐篇幅太長,OAuth 的誕生背景就不在這裏贅述了,可參考 The OAuth 2.0 Authorization Framework

  四種角色定義

  1. Resource Owner:資源所有者,即終端用戶
  2. Resource server:資源服務器,即提供資源存儲訪問一方
  3. Client:通常指第三方應用
  4. Authorization server:授權服務器

  協議端點(URI):OAuth給授權過程定義了Authorization、Token和Redirection三種端點。Authorization端點用來完成用戶授權,在授權碼模式(Authorization Code)隱含模式(Implicit)下被用到;Token端點用來交換與獲取access token,不能包含fragment(hash),在隱含模式(Implicit)下則無需提供該端點;Redirection端點用來接收授權憑證,Public客戶端或者Implicit授權的Confidential客戶端必須註冊其Redirection端點。

  客戶端類型:OAuth根據是否能夠進行安全認證定義了兩種客戶端類型:機密型客戶端(Confidential)和公開型客戶端(Public)。其中機密型客戶端有Web應用,公開型客戶端包括User Agent Based和Native應用。客戶端的類型註冊時確定,不能由授權服務器假定。如果一套應用包含多個不同類型的客戶端,這些不同部分應分開單獨註冊。

  客戶端認證(Client Authentication):客戶端認證當滿足授權服務器的安全要求,對機密型客戶端的認證可依賴授權服務器發佈的認證憑證(比如Password, Public/Private密鑰對),而要對公共客戶端進行認證很可能是不可靠的。客戶端在每次請求中只能使用一種認證方法,如果客戶端持有Password,可採用HTTP Basic認證或request-body傳遞身份憑證參數方法。客戶端認證帶來的益處:

  1. 強制綁定Refresh Token或Authorization Code到客戶端
  2. 通過禁用或修改其憑證來快速恢復淪陷客戶端
  3. 定期憑證輪換,更容易實現認證管理

  訪問令牌(Access Token)是什麼?Access Token是訪問被保護資源的憑證,一個用來表明被授予權限的字符串,可以是一種可取回授權信息的標識,也可以自包含授權信息於內。可參考 RFC6750 - OAuth 2.0 Bearer Token Usage 。

  更新令牌(Refresh Token)是什麼?當Access Token無效或過期後,客戶端將使用Refresh Token來請求授權服務器更新Access Token,除此而外別無他用。通常Refresh Token是授權服務器在發佈新Access Token的同時可選發佈的,與客戶端綁定並長期有效,但是隻有授權碼模式(Authorization Code)用戶密碼模式(Resource Owner Password Credentials)支持Refresh Token。授權服務器須執行如下操作:

  1. 對於認證型客戶端,要求進行認證
  2. 如果請求中包含客戶端認證,則執行認證流程,還要保證Refresh Token是發佈給認證客戶端的
  3. 驗證Refresh Token是否有效

  Transport Layer Security (TLS):授權服務器和資源服務器都必須實現TLS,至於客戶端最好也實現TLS。如果客戶端沒有實現TLS,授權服務器在發出重定向之前應向用戶發出安全告警信息。

  OAuth授權的基本流程如下

  

  1. 用戶打開客戶端以後,客戶端要求用戶給予授權
  2. 用戶同意給予客戶端授權
  3. 客戶端使用上一步獲得的授權,向授權服務器申請令牌
  4. 授權服務器對客戶端進行授權以後,確認無誤,同意發放令牌
  5. 客戶端使用令牌,向資源服務器申請獲取資源
  6. 資源服務器確認令牌無誤,同意向客戶端開放資源

  OAuth針對不同場景詳細定義了四種授權模式:授權碼模式(Authorization Code)、隱含模式(Implicit)、用戶密碼模式(Resource Owner Password Credentials)和客戶端證書模式(Client Credentials)。另外,你也可以使用其他擴展模式。

 

一. 授權碼模式(Authorization Code)

  授權碼模式是流程最嚴密的授權模式,但是如果被用於Public客戶端授權,由於該客戶端不能持有客戶端證書,因此無法進行身份認證。

  • 流程解析: 
    1. 用戶訪問客戶端,後者將前者導向授權服務器
    2. 用戶選擇是否給予客戶端授權
    3. 假設用戶給予授權,授權服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個授權碼
    4. 客戶端收到授權碼,附上早先的"重定向URI",向授權服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見
    5. 授權服務器覈對了授權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)或者更新令牌(refresh token)

  該流程中客戶端先獲取授權碼再交換訪問令牌,似乎獲取授權碼顯得多餘?其實授權碼除了代表授權範圍之外,還避免了暴露訪問令牌於用戶端

The authorization code provides a few important security benefits,such as the ability to authenticate the client, as well as the transmission of the access token directly to the client without passing it through the resource owner's user-agent and potentially exposing it to others, including the resource owner

 

二. 隱含模式(Implicit)

  授權碼模式的簡化版,跳過了"授權碼"這一步,可適用於在瀏覽器中實現的應用,訪問令牌暴露於用戶端;在該模式下,授權服務器不會認證客戶端,不能使用Refresh Token,一旦Access Token過期,需要重新進行授權處理;隱含模式是一個基於redirection的流,在某些情況下,客戶端身份是可以通過redirection URI來驗證的。在授權碼模式可用的情況下,應權衡隱含模式的便利性和安全性。

  • 流程解析
    1. 客戶端將用戶導向認證服務器
    2. 用戶決定是否給於客戶端授權
    3. 假設用戶給予授權,認證服務器將用戶導向客戶端指定的"重定向URI",並在URI的Hash部分包含了訪問令牌
    4. 瀏覽器向Web-Hosted服務器發出請求,其中不包括上一步收到的Hash值
    5. Web-Hosted服務器返回一個網頁,其中包含的代碼可以獲取Hash值中的令牌
    6. 瀏覽器執行上一步獲得的腳本,提取出令牌
    7. 瀏覽器將令牌發給客戶端

  • 流程參數解釋:此處不再詳述,可參考理解OAuth 2.0 或 RFC6749

 

三. 用戶密碼模式(Resource Owner Password Credentials)

  用戶向客戶端提供自己的用戶名和密碼,客戶端使用這些信息向授權服務器索要授權,但不得保存用戶的密碼。須在用戶對客戶端高度信任(比如客戶端是操作系統的一部分,或者由一個著名公司出品,或者客戶端是本公司出品),而認證服務器無法在其他授權模式下完成授權的情況下,才能考慮使用這種模式。

  • 流程解析
    1. 用戶向客戶端提供用戶名和密碼
    2. 客戶端將用戶名和密碼發給認證服務器,向後者請求令牌
    3. 認證服務器確認無誤後,向客戶端提供訪問令牌

 

四. 客戶端證書模式(Client Credentials)

  顧名思義,客戶端模式不是針對單個用戶的授權,而是針對客戶端授權,適用於受保護資源已經處於客戶端控制之下(相當於資源所有者)或者授權服務器已經預先配置好客戶端訪問權限的的情況。

  • 流程解析
    1. 客戶端向認證服務器進行身份認證,並要求一個訪問令牌
    2. 認證服務器確認無誤後,向客戶端提供訪問令牌

  • 流程參數解釋:此處不再詳述,可參考理解OAuth 2.0 或 RFC6749

 

五. 授權模式選擇

  • 本公司出品應用一般適用用戶密碼模式(Resource Owner Password Credentials)
  • Web應用一般適用授權碼模式(Authorization Code)
  • Native應用一般適用授權碼模式(Authorization Code)或隱含模式(Implicit):Native應用指安裝、運行在用戶設備上的客戶端,包括桌面應用、手機客戶端等
    When choosing between the implicit grant type and the authorization code grant type, the following should be considered:
    
    . Native applications that use the authorization code grant type SHOULD do so without using client credentials, due to the native application's inability to keep client credentials confidential.
    . When using the implicit grant type flow, a refresh token is not returned, which requires repeating the authorization process once  the access token expires.
  • User Agent Based應用一般適用隱含模式(Implicit)

  • 機器對機器一般適用客戶端證書模式(Client Credentials) 

 

六. OAuth不是認證協議

OAuth消費認證(Authentication)而不提供認證,因此OAuth必須結合第三方認證協議如 OpenID Connect:OAuth 2.0協議之上的簡單身份層 纔可使用。但OAuth協議中確實有些內容說的就是認證事件,給人的感覺就是它已定義了認證流程,當然也就算是有效的認證協議了,這是很容易讓人誤解的;其實啊,定義認證流根本就不是OAuth的題中之意(比如用戶註冊這個認證流中的重要環節就不是OAuth所關心的內容,所以也就不曾定義)。下邊的引文來自 The OAuth 2.0 Authorization Framework :

Before initiating the protocol, the client registers with the
authorization server.  The means through which the client registers
with the authorization server are beyond the scope of this
specification but typically involve end-user interaction with an HTML
registration form. 

只是認證和授權硬生生地割裂開來,井水不犯河水是不可能的,所以OAuth裏邊也只是簡單地提到了與授權流相關的認證流要害節點以使授權流的定義完整,而沒有詳細定義認證流,這也是本人剛開始認爲OAuth是一個弱認證授權協議的原因。下邊的引用文字來自 User Authentication with OAuth 2.0

OAuth 2.0 is not an authentication protocol.

an OAuth process does usually include several kinds of authentication in its process:

the resource owner authenticates to the authorization server in the authorization step,

the client authenticates to the authorization server in the token endpoint, and there may be others.

The existence of these authentication events within the OAuth protocol does not translate to the

Oauth protocol itself being able to reliably convey authentication.

假如OAuth可以完全拋棄所涉及的任何認證流部分,也就不會有人認爲OAuth也是認證協議了,而一個完整的認證協議應該是這樣的:

Authentication in the context of a user accessing an application tells an application who

the current user isand whether or not they're present. A full authentication protocol will probably

also tell you a number of attributes about this user, such as a unique identifier, an email address,

and what to call them when the application says "Good Morning". Authentication is all about the

user and their presence with the application, and an internet-scale authentication protocol needs

to be able to do this across network and security boundaries.

  

七. 採用OAuth認證常見陷阱

  • Access Token作爲訪問受保護的資源身份認證的證明:Token應該包含Client可理解和解析的結構,如同時使用Client可理解和解析ID Token。
  • Access Token作爲訪問UserInfo API身份認證的證明:通常在用戶不存在後,Access Token通常還會存在很長時間,如果一個Client想要確保身份認證是有效的,那麼簡單的使用Access Token獲取用戶信息是不夠的。
  • Access Token注入:這可能會發生在使用Implicit流程中,並且Client不正確使用state參數的時候;對此可以使用Authorization Code來緩解這一點,並且只能通過授權服務器的Token API並使用一個state的值來避免被攻擊者猜中。
  • Access Token缺乏Client受衆限制:通過將Client的認證信息與Client可以識別和驗證的標識符一起傳遞給Client,可以緩解此問題,從而允許客戶端區分自身的身份認證與另一應用程序的身份認證。
  • 對UserInfo API響應結果注入無效的用戶信息:如果攻擊者能夠攔截或者替換來自Client的一個調用,它可能會改變返回的用戶信息,而客戶端卻無法感知這一情況;對此可通過在身份認證協議過程中(比如跟隨OAuth的Token的頒發過程)直接從身份提供程序中獲取身份認證信息,並通過可校驗的簽名保護身份認證信息,可以緩解這一問題。
  • 不同身份認證提供商實現了不同的身份認證協議:基於OAuth 身份(identity)API的最大問題在於,即使使用完全符合OAuth的機制,不同的身份認證提供程序不可避免的會使用不同方式實現身份(identity)API。OAuth定義了一個沒有特定格式的token,一個沒有通用範圍的access token,並且沒有解決受保護資源如何驗證access token。

 

八. 安全風險

  • 客戶端認證(Client Authentication):對Public客戶端進行認證很可能是不可靠的,授權服務器可以嘗試使用redirection URI或徵募用戶來驗證客戶端身份
       The authorization server MUST NOT issue client passwords or other
       client credentials to native application or user-agent-based
       application clients for the purpose of client authentication.  The
       authorization server MAY issue a client password or other credentials
       for a specific installation of a native application client on a
       specific device.
       ......
       A valid
       redirection URI is not sufficient to verify the client's identity
       when asking for resource owner authorization but can be used to
       prevent delivering credentials to a counterfeit client after
       obtaining resource owner authorization.
  • 更新令牌(Refresh Tokens):授權服務器可以給Web客戶端和Native客戶端發佈Refresh Token。Refresh Token在整個生命週期中都應該保持機密性,不能泄露給任何無關的第三方;Refresh Token必須與客戶端身份相綁定;Refresh Token不能未獲授權而被生成、修改、猜測產生

      the authorization server could employ refresh token
       rotation in which a new refresh token is issued with every access
       token refresh response.  The previous refresh token is invalidated
       but retained by the authorization server.  If a refresh token is
       compromised and subsequently used by both the attacker and the
       legitimate client, one of them will present an invalidated refresh
       token, which will inform the authorization server of the breach
  • 授權碼(Authorization Codes):授權碼有效期短,單一用途

       If the
       authorization server observes multiple attempts to exchange an
       authorization code for an access token, the authorization server
       SHOULD attempt to revoke all access tokens already granted based on
       the compromised authorization code.
  • 跨站請求僞造(Cross-Site Request Forgery):一同發送一個non-guessable state請求參數可用來防止CSRF
       A CSRF attack against the client's redirection URI allows an attacker
       to inject its own authorization code or access token, which can
       result in the client using an access token associated with the
       attacker's protected resources rather than the victim's (e.g., save
       the victim's bank account information to a protected resource
       controlled by the attacker).
    
       The client MUST implement CSRF protection for its redirection URI.
       This is typically accomplished by requiring any request sent to the
       redirection URI endpoint to include a value that binds the request to
       the user-agent's authenticated state (e.g., a hash of the session
       cookie used to authenticate the user-agent).  The client SHOULD
       utilize the "state" request parameter to deliver this value to the
       authorization server when making an authorization request.
  • 點擊劫持(Clickjacking)
      To prevent this form of attack, native applications SHOULD use
       external browsers instead of embedding browsers within the
       application when requesting end-user authorization.  For most newer
       browsers, avoidance of iframes can be enforced by the authorization
       server using the (non-standard) "x-frame-options" header.  This
       header can have two values, "deny" and "sameorigin", which will block
       any framing, or framing by sites with a different origin,
       respectively.  For older browsers, JavaScript frame-busting
       techniques can be used but may not be effective in all browsers

 

九. 相關參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章