簡單理解OAuth 2.0

Magic_Duck發表於2018-07-03

個人部落格地址:blog.sqdyy.cn

OAuth2要解決的問題

開放系統間授權問題

OAuth2最初是基於開放系統間授權問題提出的,假設現在有一個第三方應用:“雲沖印服務”,可以將使用者儲存在Google的照片沖印出來。使用者為了使用該服務,必須讓“雲沖印服務”讀取自己儲存在Google上的照片。問題是隻有得到使用者的授權,Google才會同意“雲沖印服務”讀取這些照片。那麼“雲沖印服務”如何獲取使用者的授權呢?

辦法1:密碼使用者名稱複製

辦法1密碼使用者名稱複製

傳統的辦法是,資源擁有者將自己的使用者名稱和密碼告訴第三方服務,然後第三方服務再去讀取使用者受保護的資源,這種做法適用於公司內部應用開發時使用,在開放系統間這麼做就不太合適了,因為第三方服務可能為了後續的服務,會儲存使用者的密碼,這樣很不安全。

辦法2:萬能鑰匙

辦法2萬能鑰匙

另一種方法是客戶應用和受保護的資源之間商定一個通用developer key,使用者在受保護資源方得到一個developer key交給第三方應用,第三方應用再通過這個developer key去訪問使用者受保護的資源。這種方式適用客戶應用和受保護資源之間存在信任關係的情況,如兩方是合作商,或是同個公司不同部門之間的應用。但是對於不受信的第三方應用來說這種方法也不合適。

辦法3:特殊令牌

辦法3特殊令牌

第三種方法是使用一個特殊令牌,它僅僅能訪問受保護的資源,這種做法相對前兩種方法要靠譜的多,並且和OAuth2的做法已經比較接近了,但是如何管理令牌,頒發令牌,吊銷令牌就需要一些講究了,這些我們留到後面介紹OAuth2再來了解。

現代微服務安全問題

傳統單塊應用的架構中,通常我們的單塊應用會部署到應用伺服器做成叢集,其中會有一個專門用於處理登入授權的使用者資料庫。當使用者訪問應用伺服器時,會通過應用的攔截器進行攔截鑑權,如果鑑權登入成功,通常由伺服器發給客戶端一個會話標識Session ID,客戶端將Session ID儲存在Cookie中,伺服器記錄Session ID與經過驗證的使用者的對應關係。

傳統單塊應用架構

相對而言,傳統單塊應用主要是直接面向PC使用者的Web應用,對於現代微服務架構而言,上面的做法就不適用了。對於現代微服務架構而言,服務之間拆分的粒度較小,需要考慮服務和服務之間的鑑權問題,另外就是應用的形態變得多種多樣,例如有單頁應用,無線原生APP,服務端APP。這種場景下我們通常會設計一個獨立的服務,將認證和授權都做成一個AuthServer,通過Token的形式進行鑑權和授權,那麼這也是OAuth2解決的一個主要問題,我們將在後面進行介紹。

現代微服務架構


OAuth的基本概念

OAuth2.0是用於REST/APIs的代理授權框架(delegated authorization framework),它基於令牌Token的授權,在無需暴露使用者密碼的情況下,使應用能獲取對使用者資料的有限訪問許可權。Oauth2.0能將認證和授權解耦,它是事實上的標準安全框架,支援多種應用場景,如服務端WebApp,瀏覽器單頁應用SPA,無線/原生App,伺服器對伺服器之間呼叫等等。

OAuth2.0具有以下優勢:

  • 客戶端不接觸使用者密碼,服務端更易集中保護
  • 廣泛傳播並被持續採用
  • 支援短壽命和封裝的Token
  • 資源伺服器和授權伺服器解耦
  • 集中式授權,簡化客戶端
  • HTTP/JSON友好,易於請求和傳遞Token
  • 考慮多種客戶端架構場景
  • 客戶端可以具有不同的信任級別

OAuth2.0的不足:

  • 協議框架太寬泛,造成各種實現的相容性和互操作性差
  • 和OAuth1.0不相容

OAuth需要注意的地方:

  • OAuth並沒有支援HTTP以外的協議
  • OAuth並不是一個認證協議
  • OAuth並沒有定義授權處理機制
  • OAuth並沒有定義Token型別
  • OAuth2.0並沒有定義加密方法
  • OAuth2.0並不是單個協議。
  • OAuth2.0僅是授權框架,僅用於授權代理。

OAuth主要角色和術語

OAuth2主要角色

  • Client Application(客戶應用):通常是一個Web或者無線應用,它需要訪問使用者的受保護資源。
  • Resource Server(資源伺服器):是一個Web站點或者Web service API,使用者的受保護資料儲存在此。
  • Authorized Server(授權伺服器):在客戶應用成功認證並獲得授權之後,向客戶應用頒發訪問令牌Access Token。
  • Resource Owner(資源擁有者):資源的擁有人,想要分享某些資源給第三方應用。
  • Client Credentials(客戶憑證):客戶的clientId和密碼用於認證客戶。
  • Tokens(令牌):授權伺服器在接收到使用者請求以後,頒發訪問令牌。
  • Scopes(作用域):客戶請求訪問令牌時。由資源擁有者額外指定細分許可權(permission)

OAuth令牌型別

令牌Token是OAuth2.0的核心概念,令牌可以類比為一把僕從鑰匙(Valet Key),它給應用授權有限的訪問許可權,讓應用能夠代表使用者去訪問使用者的資料。

  • Authorization Code Token(授權碼):僅用於授權碼授權型別,用於交換獲取訪問令牌和重新整理令牌。
  • Refresh Token(重新整理令牌):用於去授權伺服器獲取一個新的令牌。
  • Access Token(訪問令牌):用於代表一個使用者或服務直接去訪問受保護的資源。
  • Bearer Token:不管是誰拿到Token都可以訪問資源。
  • Proof of Possession(Pop) Token:可以校驗client是否對Token有明確的擁有權。

OAuth2授權方式

先來看OAuth2.0的執行流程:

OAuth2.0的執行流程

  • (A)使用者開啟客戶端以後,客戶端要求使用者給予授權。
  • (B)使用者同意給予客戶端授權。
  • (C)客戶端使用上一步獲得的授權,向認證伺服器申請令牌。
  • (D)認證伺服器對客戶端進行認證以後,確認無誤,同意發放令牌。
  • (E)客戶端使用令牌,向資源伺服器申請獲取資源。
  • (F)資源伺服器確認令牌無誤,同意向客戶端開放資源。

這裡的B步驟是關鍵,即客戶如何給客戶的授權,有了這個授權後客戶端就可以獲取令牌,進而憑藉令牌獲取資源,OAuth2.0為我們提供了4種客戶端獲取授權的模式:

  • 授權碼模式(Authorization Code)
  • 簡化模式(implicit)
  • 密碼模式(resource owner password credentials)
  • 客戶端模式(client credentials)

授權碼模式

授權碼模式相對其他三個模式來說是功能最完整,流程最安全嚴謹的授權方式。它的特點是通過客戶端的後臺伺服器與服務提供商的認證伺服器進行互動:

授權碼模式

它的步驟如下:

  • (A)使用者訪問客戶端,客戶端將使用者導向認證伺服器,需要攜帶客戶端ID憑證和重定向URI。
  • (B)使用者選擇是否給予客戶端授權。
  • (C)假設使用者給予授權,認證伺服器將使用者導向事先指定的重定向URI,同時附上一個授權碼。
  • (D)客戶端收到授權碼後,在後臺伺服器(對使用者不可見)攜帶事先指定的重定向URI和授權碼向認證伺服器申請令牌。
  • (E)認證伺服器核對授權碼和重定向URI,確認無誤後,向客戶端頒發訪問令牌(access token)和重新整理令牌(refresh token)。

簡化模式

簡化模式不通過服務端程式來完成,比授權碼模式減少了“授權碼”這個步驟,直接由瀏覽器傳送請求獲取令牌,令牌對訪問者是可見的,且客戶端不需要認證,這種模式一般用於單頁應用:

簡化模式

它的步驟如下:

  • (A)使用者訪問客戶端,客戶端將使用者導向認證伺服器,需要攜帶客戶端ID憑證和重定向URI。
  • (B)使用者選擇是否給予客戶端授權。
  • (C)假設使用者給予授權,認證伺服器將使用者導向事先指定的重定向URI,並在URI的Hash部分包含了訪問令牌(Fragment)。
  • (D)瀏覽器向資源伺服器發出請求,其中不包含事先收到的Hash部分(Fragment)。
  • (E)資源伺服器返回一段指令碼,其中包含的程式碼可以獲取Hash部分中的令牌。
  • (F)瀏覽器執行事先獲取的指令碼,提取出令牌
  • (G)瀏覽器將令牌傳送給客戶端。

密碼模式

密碼模式中,使用者向客戶端提供使用者名稱和密碼,客戶端使用這些資訊,直接向認證伺服器索要授權。這種模式違背了前面提到的微服務安全要解決的問題(不暴露使用者名稱和密碼),但是在一些使用者對客戶端高度信任的情況下,例如公司內部軟體間的授權下,使用這種模式也是適用的:

密碼模式

它的步驟如下:

  • (A)使用者向客戶端提供使用者名稱和密碼。
  • (B)客戶端將使用者名稱和密碼傳送給認證伺服器,向認證伺服器索要令牌。
  • (C)認證伺服器確認無誤後,向客戶端提供訪問令牌。

客戶端模式

客戶端模式是客戶端以自己的名義去授權伺服器申請授權令牌,並不是完全意義上的授權。主要應用於Docker到DokcerHub拉取映象的這類場景:

客戶端模式

它的步驟如下:

  • (A)客戶端向認證伺服器進行身份認證,並要求獲取訪問令牌。
  • (B)認證伺服器確認無誤後,向客戶端提供訪問令牌。

重新整理令牌

如果使用者訪問的時候,客戶端的"訪問令牌"已經過期,則需要使用"更新令牌"申請一個新的訪問令牌:

重新整理令牌

它的步驟如下:

  • (A)客戶端向認證伺服器進行身份認證,並要求獲取訪問令牌。
  • (B)認證伺服器確認無誤後,返回訪問令牌和一個重新整理令牌。
  • (C)客戶端通過訪問令牌訪問受保護資源。
  • (D)如果訪問令牌未過期,則向客戶端提供資源服務。
  • (E)客戶端通過訪問令牌訪問受保護資源。
  • (F)如果訪問令牌過期,受保護資源伺服器返回Invalid Token Error。
  • (G)客戶端得到上方的錯誤後,通過重新整理令牌向授權伺服器申請一個新的訪問令牌。
  • (H)認證伺服器確認無誤後,返回訪問令牌和一個重新整理令牌。

OAuth2.0四種模式的選型

上面介紹了OAuth4種客戶端授權模式,下面介紹這4種模式的技術選型,在這之前先做兩個概念鋪墊:

授權流程渠道(channels): 前面提到了OAuth2的四個主要角色,這四個角色之間的互動可以劃分成兩類渠道,凡是資源擁有者、客戶應用和授權伺服器之間的傳送互動可以劃分為 前端渠道。凡是授權伺服器、客戶應用和資源伺服器之間發生的互動可以劃分為後端渠道

OAuth2主要角色

客戶應用型別:客戶應用也可以劃分為兩類應用,第一類是公開應用,主要是指單頁應用SPA或原生App應用,這類應用都是駐在使用者手中的,這種應用不能將使用者的憑證資訊如密碼駐留在上面,一般只存使用者標識。第二類是私密應用,主要指Web服務端應用、服務/API(機器對機器間),這種應用是在後端執行的,整體上相對安全,可以駐留使用者憑證資訊。

四種OAuth2.0授權模式的特徵

在選型之前我們先來彙總一下四種授權型別的特徵:

授權碼模式

  • 通過前端渠道客戶獲取授權碼
  • 通過後端渠道,客戶使用授權碼去交換訪問令牌和重新整理令牌
  • 假定資源擁有者和客戶在不同裝置上
  • 最安全的流程,因為令牌不會傳遞經過user-agent

簡化模式

  • 適用於公開的瀏覽器單頁應用
  • access token直接從授權伺服器返回(只有前端渠道)
  • 不支援refresh token
  • 假定資源所有者和公開應用在同一個應用上
  • 最容易受到安全攻擊

使用者名稱密碼模式

  • 使用使用者名稱密碼登入的應用,例如桌面App,內部軟體
  • 使用使用者名稱/密碼作為授權方式從授權伺服器上獲取access token
  • 一般不支援refresh token
  • 假定資源擁有者和公開使用者在相同裝置上

客戶端模式

  • 適用於伺服器間通訊廠家,機密客戶代表它自己或者一個使用者
  • 只有後端渠道,使用客戶憑證獲取一個access token
  • 因為客戶憑證可以使用對稱或非對稱加密,該方式支援共享密碼或者證書

授權模式選型

綜合上述,在選型時可以參考下面流程圖的思路:

授權模式選型

本文參考資料:

相關文章