OAuth 2.0 / RCF6749 協議解讀

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

  四種角色定義git

  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端點。promise

  客戶端類型: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。受權服務器須執行以下操做:cookie

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

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

  OAuth受權的基本流程以下app

  

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

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

 

一. 受權碼模式(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

 

九. 相關參考

相關文章
相關標籤/搜索