OAuth:每次授權暗中保護你的那個“MAN”

華為雲開發者社群發表於2021-02-18
摘要:OAuth是一種授權協議,允許使用者在不將賬號口令洩露給第三方應用的前提下,使第三方應用可以獲得使用者在某個web服務上存放資源的訪問許可權。

背景

在傳統模式下,使用者的客戶端在訪問某個web服務提供的具有一定訪問限制的資源時,需要提供用於進行身份認證的憑證(credential),例如密碼,accesskey等。如果存在第三方的應用需要該web服務上使用者的資源,使用者必須將自己的憑證共享給第三方應用,這種實踐帶來了一些問題:

  1. 第三方應用需要存放使用者的憑證,且必須拿到明文(例如使用使用者名稱和密碼遠端呼叫web服務的API),如果第三方應用被攻擊,使用者的憑證可能被洩露。
  2. 無法限制第三方應用的許可權。第三方應用拿到使用者憑證明文後,等於拿到了使用者的所有許可權,且使用者無法對第三方應用在什麼時間訪問哪些資源進行限制,可能被越權。
  3. 使用者無法回收對某個第三方應用的授權,除非更改密碼。更改密碼可能導致依賴該密碼的其他第三方應用無法訪問。
  4. 使用者資源的安全性取決於安全性最弱的第三方應用(木桶理論),任何一個第三方應用被攻擊,都可能導致使用者的身份憑證洩露,以及存放在web服務上的資源被攻擊。

基本原理

OAuth是一種授權協議,允許使用者在不將賬號口令洩露給第三方應用的前提下,使第三方應用可以獲得使用者在某個web服務上存放資源的訪問許可權。

例如下圖,通過華為賬號登入騰訊新聞應用時,並不需要將賬號口令提供給騰訊新聞應用,使用者只要擁有華為賬號,只需要輕輕點選一下授權就可以無縫訪問,在保證安全和隱私的同時帶來體驗上質的飛躍,體驗提升的持續追求使得OAuth協議在網際網路得到了非常廣泛的應用。

OAuth:每次授權暗中保護你的那個“MAN”

OAuth通過引入authorization server的概念,並對授權訪問過程中的幾個參與方進行重新定義和角色解耦。

OAuth:每次授權暗中保護你的那個“MAN”

上面是一個非常非常抽象的流程圖,僅僅為了釐清OAuth互動過程中存在哪些角色及承擔的職責,實際上具體應用過程中的差異非常大。從上圖大概可以看出,OAuth協議互動過程中存在四種角色:

  • resource owner

需要訪問資源的主體,可以是人,也可以是物,指代人的時候就是我們通常說的end-user。

  • resource server

存放受保護資源的web服務,接收資源的訪問請求並響應,resource server對請求進行鑑權。例如使用者存放照片的華為終端雲服務。

  • client

用來代理resource owner請求資源的應用程式,client訪問資源需要得到resource owner的授權。例如照片美圖APP,需要拉取使用者存放在雲服務上的照片。

  • authorization server

對resource owner進行身份認證和鑑權,並頒發訪問憑證。例如華為賬號認證服務。

其他說明

  1. OAuth協議當前已經發展到0版本。1.0版本已經廢棄,且OAuth2.0並不能後向相容1.0。
  2. OAuth協議常用於web訪問,基於HTTP協議。實際上,OAuth只是定義了一種流程,以及該流程中各方的角色定義和功能職責,並不限於HTTP這一種傳輸通道。
  3. 上面的流程圖中並沒有介紹resource server和authorization server之間的互動,它們可能承載在同一個web服務中,也可能由不同的獨立web服務承載。當resource server和authorization server各自獨立時,正是因為OAuth協議沒有定義其互動過程,導致OAuth協議在產品標準化和工程化中出現困難,後面會慢慢介紹。

OAuth:授權流程

接下來我們探討一下,獲取授權和獲取token的幾種模式,應用場景,互動過程以及API的定義。

分類

OAuth:每次授權暗中保護你的那個“MAN”

準備工作

在開始OAuth2.0的授權流程前,應用的開發者需要將應用的資訊註冊到authorization server,例如華為賬號服務、百度開發者中心這些知名的開放平臺,註冊成功後得到最重要的兩個引數:client_id和client_secret,這兩個引數在後面介紹的幾乎每種授權流程都會頻繁使用。

如下圖華為終端開發者聯盟管理中心註冊介面:

OAuth:每次授權暗中保護你的那個“MAN”

開發者進行應用註冊時,一般需要提交應用型別。應用型別常見的幾大類:

OAuth:每次授權暗中保護你的那個“MAN”

對於web application,開發者還需要提交redirect URI,即web application接收grant code的地址,authorization server在認證完成後重定向到此地址。

授權碼流程

授權碼流程是oauth2.0最常見的互動流程,甚至很多開放平臺僅支援這一種流程。授權碼流程示意見下圖:

OAuth:每次授權暗中保護你的那個“MAN”

該流程主要適用於web應用,基於瀏覽器的重定向能力實現整個互動過程。

錯誤返回

當resource-owner拒絕client的訪問請求,或者授權請求錯誤,authorization server將錯誤資訊通過redirect_uri返回給client應用,除非redirect_uri本身就不正確。

引數

OAuth:每次授權暗中保護你的那個“MAN”

說明,所有引數需經過“application/x-www-form-urlencoded”編碼。

隱式授權(Implicit Grant)

如上面介紹,隱式授權適用於程式碼執行在客戶端上的應用,例如網頁應用,利用瀏覽器的重定向能力得到resource-owner的授權。不同於授權碼流程,隱式授權流程的授權請求可以直接得到access token,沒有authorization code的中間過程。隱式授權過程發生在resource owner的裝置上,必須有resource owner在場,且client程式碼不能包含client的憑證(client_secret),另外access_token返回給client時,存在暴露到同一個裝置(user-agent)上其他應用的風險。

身份資訊透傳授權(Resource Owner Password Credentials Grant)

如果resource owner非常信任這個應用,可以將身份憑證(口令,金鑰等)通過應用傳遞到authorization server。一般不推薦這種方式,應用可以截留使用者的身份憑證明文,風險較高,RFC協議也僅建議用於存量的應用遷移到OAuth協議。個人認為,如果client本身就是authorization server,其身份驗證過程這樣做也是可行的,相當於authorization server的內部實現。

OAuth:每次授權暗中保護你的那個“MAN”

客戶端憑證直接授權(Client Credentials Grant)

應用拿著client_id和client_secret直接從authorization server獲取access token,這種流程僅用於訪問應用本身的與resource owner無關的資料,不需要resource owner授權的場景,可以使用這種授權,一般都是機機介面呼叫。

擴充套件應用

不同廠商的開放平臺可以擴充套件授權流程,以滿足不能場景的需求,例如手機、平板等端側裝置應用,或者電視、遊戲手柄等娛樂裝置應用。

移動端和PC桌面的應用授權

對於執行在手機、平臺和PC上的應用程式,也可以通過OAuth協議得到使用者的授權來安全的訪問使用者的資料。這種場景的授權流程和web server應用非常類似,也是authorization grant模式,主要區別是此類應用需要提供本地web server或者支援應用間跳轉,並提供系統內建的“browser”(例如android的intent)實現與authorization server之間的互動。

這種授權方式的互動過程和介面和上文介紹得authorization grant模式一樣,唯獨授權請求的redirect_uri引數有差異:

OAuth:每次授權暗中保護你的那個“MAN”

電視或輸入受限裝置的應用授權

當我們在使用智慧電視、遊戲手柄或者帶液晶屏的印表機需要訪問使用者的資料,例如放在網盤上的照片、文件等,需要得到使用者的授權,而這類裝置的輸入能力有限,沒有瀏覽器進行重定向,也不方便輸入賬號口令等認證憑證。

此類場景的應用授權大致步驟如下:

OAuth:每次授權暗中保護你的那個“MAN”

Step1: 獲取device_code

-

Java 程式碼

1
POST /device/code
2
Content-Type: application/x-www-form-urlencoded
3
4
client_id=client_id&response_type=device_code&scope=email%20profile 

Step2: 處理authorization響應

-

Java 程式碼

{
    "device_code": "4/4-GMMhhdfkdkfgdgegkfkfkeegjgjgj",
    "user_code": "GQVQ-JKEC",
    "verification_url": "https://www.google.com/device",
"qrcode_url": "http://www.google.com/device/qrcode\ddggheghehhhdddddddddddddddhgerhh",   //二維碼
    "expires_in": 1800    // code有效期
    "interval": 5   // poll的間隔

Step3: 顯示user_code

可以螢幕顯示verification_url和user_code,甚至如果支援的話可以顯示二維碼。

Step4:poll使用者授權結果

APP根據第2步授權響應的interval間隔,向authorization server 拉取使用者的授權結果。

-

Javascript 程式碼

POST /token
Content-Type: application/x-www-form-urlencoded
 
client_id={client_id}&
client_secret={client_secret}&
code={device_code}&
grant_type=device_code

Step5: 使用者開啟瀏覽器輸入verification_url和user_code,或者通過手機掃碼完成登入和授權。

Step6: 處理poll 響應

Javascript 程式碼

{
    "access_token": "1/ffffdgdg",  
    "expires_in": 3920,
    "scope": "openid profile email",
    "token_type": "Bearer",
    "refresh_token": "dgegegegedgegeg"

}

OAuth:API定義和擴充套件

在上一篇中介紹了不同場景下的應用獲得租戶授權的互動流程。本文主要介紹OAuth2.0協議的授權和token API定義及常見的擴充套件方案。OAuth2.0的所有引數都通過"urlencoded"編碼,在請求頭部需要增加“application/x-www-form-urlencoded”。

1. code授權請求API

適用於authorization code grant模式,應用通過瀏覽器將授權請求重定向給authorization server,除了通過重定向外,我認為也可以通過FORM表單提交。

1.1 引數

OAuth:每次授權暗中保護你的那個“MAN”

1.2 示例

GET /oauth2/authorize?response_type=code&

client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

1.3 擴充套件

看了Google的OAuth2.0介面定義,選取幾個實踐中比較有意義的擴充套件引數:

OAuth:每次授權暗中保護你的那個“MAN”

1.4 響應

authorization server完成使用者身份認證並得到使用者授權後,將code作為引數重定向給redirect_uri。

OAuth:每次授權暗中保護你的那個“MAN”

2. 隱式授權請求API

適用於implicit grant模式,瀏覽器JS直接向authorization server傳送授權請求。

2.1 引數

OAuth:每次授權暗中保護你的那個“MAN”

2.2 示例

   GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
    Host: server.example.com

2.3 響應

認證伺服器在完成使用者身份認證並得到使用者的授權後,將回跳到redirect_uri,並攜帶access_token引數。

OAuth:每次授權暗中保護你的那個“MAN”

API定義和擴充套件

OAuth2.0的所有引數都通過"urlencoded"編碼,在請求頭部需要增加“application/x-www-form-urlencoded”。

1. code授權請求API

適用於authorization code grant模式,應用通過瀏覽器將授權請求重定向給authorization server,除了通過重定向外,我認為也可以通過FORM表單提交。

1.1 引數

OAuth:每次授權暗中保護你的那個“MAN”

1.2 示例

GET /oauth2/authorize?response_type=code&

client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

 

1.3 擴充套件

看了Google的OAuth2.0介面定義,選取幾個實踐中比較有意義的擴充套件引數:

OAuth:每次授權暗中保護你的那個“MAN”

1.4 響應

authorization server完成使用者身份認證並得到使用者授權後,將code作為引數重定向給redirect_uri。

OAuth:每次授權暗中保護你的那個“MAN”

2. 隱式授權請求API

適用於implicit grant模式,瀏覽器JS直接向authorization server傳送授權請求。

2.1 引數

OAuth:每次授權暗中保護你的那個“MAN”

2.2 示例

  GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
    Host: server.example.com

2.3 響應

認證伺服器在完成使用者身份認證並得到使用者的授權後,將回跳到redirect_uri,並攜帶access_token引數。

OAuth:每次授權暗中保護你的那個“MAN”

本文分享自華為雲社群《【系列集合篇】淺談OAuth二三事》,原文作者:APTX-486977。

 

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章