你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> 幫你深入理解OAuth2.0協議

幫你深入理解OAuth2.0協議

編輯:關於IOS

1. 引言

如果你開車去酒店赴宴,你經常會苦於找不到停車位而耽誤很多時間。是否有好辦法可以避免這個問題呢?有的,聽說有一些豪車的車主就不擔心這個問題。豪車一般配備兩種鑰匙:主鑰匙和泊車鑰匙。當你到酒店後,只需要將泊車鑰匙交給服務生,停車的事情就由服務生去處理。與主鑰匙相比,這種泊車鑰匙的使用功能是受限制的:它只能啟動發動機並讓車行駛一段有限的距離,可以鎖車,但無法打開後備箱,無法使用車內其他設備。這裡就體現了一種簡單的“開放授權”思想:通過一把泊車鑰匙,車主便能將汽車的部分使用功能(如啟動發動機、行駛一段有限的距離)授權給服務生。

授權是一個古老的概念,它是一個多用戶系統必須支持的功能特性。比如,Alice和Bob都是Google的用戶,那麼Alice應該可以將自己的照片授權給Bob訪問。但請注意到,這種授權是一種封閉授權,它只支持系統內部用戶之間的相互授權,而不能支持與其他外部系統或用戶之間的授權。比如說,Alice想使用“網易印像服務”將她的部分照片沖印出來,她怎麼能做到呢?

肯定有人會說,Alice可以將自己的Google用戶名和密碼告訴網易印像服務,事情不就解決了嗎?是的,但只有毫不關注安全和隱私的同學才會出此“絕招”。那麼我們就來想一想,這一“絕招”存在哪些問題?(1) 網易印像服務可能會緩存Alice的用戶名和密碼,而且可能沒有加密保護。它一旦遭到攻擊,Alice就會躺著中槍。(2) 網易印像服務可以訪問Alice在Google上的所有資源,Alice無法對他們進行最小的權限控制,比如只允許訪問某一張照片,1小時內訪問有效。(3) Alice無法撤消她的單個授權,除非Alice更新密碼。

在以Web服務為核心的雲計算時代,像用戶Alice的這種授權需求變得日益迫切與興盛,“開放授權(Open Authorization)”也正因此而生,意在幫助Alice將她的資源授權給第三方應用,支持細粒度的權限控制,並且不會洩漏Alice的密碼或其它認證憑據。

根據應用場景的不同,目前實現開放授權的方法分為兩種:一種是使用OAuth協議[1];另一種是使用IAM服務[2]。OAuth協議主要適用於針對個人用戶對資源的開放授權,比如Google的用戶Alice。OAuth的特點是“現場授權”或“在線授權”:客戶端主要通過浏覽器去訪問資源,授權時需要認證Alice的資源所有者身份,並且需要Alice現場審批。OAuth一般在SNS服務中廣泛使用,如微博。IAM服務則不同,它的特點是“預先授權”或“離線授權”:客戶端主要通過REST API方式去訪問資源,資源所有者可以預先知道第三方應用所需要的資源請求,一次授權之後,很少會變更。IAM服務一般在雲計算服務中使用,如AWS服務、阿裡雲計算服務。

本文主要介紹OAuth開放授權。關於以IAM服務提供的開放授權,我將在另一篇博文中介紹。下面我來介紹OAuth 2.0協議、協議的實例化描述、安全性分析。
2. OAuth 2.0 協議

OAuth 2.0 是目前比較流行的做法,它率先被Google, Yahoo, Microsoft, Facebook等使用。之所以標注為 2.0,是因為最初有一個1.0協議,但這個1.0協議被弄得太復雜,易用性差,所以沒有得到普及。2.0是一個新的設計,協議簡單清晰,但它並不兼容1.0,可以說與1.0沒什麼關系。所以,我就只介紹2.0。

2.1 協議的參與者

從引言部分的描述我們可以看出,OAuth的參與實體至少有如下三個:

· RO (resource owner): 資源所有者,對資源具有授權能力的人。如上文中的用戶Alice。

· RS (resource server): 資源服務器,它存儲資源,並處理對資源的訪問請求。如Google資源服務器,它所保管的資源就是用戶Alice的照片。

· Client: 第三方應用,它獲得RO的授權後便可以去訪問RO的資源。如網易印像服務。

此外,為了支持開放授權功能以及更好地描述開放授權協議,OAuth引入了第四個參與實體:

· AS (authorization server): 授權服務器,它認證RO的身份,為RO提供授權審批流程,並最終頒發授權令牌(Access Token)。讀者請注意,為了便於協議的描述,這裡只是在邏輯上把AS與RS區分開來;在物理上,AS與RS的功能可以由同一個服務器來提供服務。
2.2 授權類型

在開放授權中,第三方應用(Client)可能是一個Web站點,也可能是在浏覽器中運行的一段JavaScript代碼,還可能是安裝在本地的一個應用程序。這些第三方應用都有各自的安全特性。對於Web站點來說,它與RO浏覽器是分離的,它可以自己保存協議中的敏感數據,這些密鑰可以不暴露給RO;對於JavaScript代碼和本地安全的應用程序來說,它本來就運行在RO的浏覽器中,RO是可以訪問到Client在協議中的敏感數據。

OAuth為了支持這些不同類型的第三方應用,提出了多種授權類型,如授權碼 (Authorization Code Grant)、隱式授權 (Implicit Grant)、RO憑證授權 (Resource Owner Password Credentials Grant)、Client憑證授權 (Client Credentials Grant)。由於本文旨在幫助用戶理解OAuth協議,所以我將先介紹這些授權類型的基本思路,然後選擇其中最核心、最難理解、也是最廣泛使用的一種授權類型——“授權碼”,進行深入的介紹。
2.3 OAuth協議 - 基本思路


[Figure 1: Abstract Protocol Flow]

如圖1所示,協議的基本流程如下:

(1) Client請求RO的授權,請求中一般包含:要訪問的資源路徑,操作類型,Client的身份等信息。

(2) RO批准授權,並將“授權證據”發送給Client。至於RO如何批准,這個是協議之外的事情。典型的做法是,AS提供授權審批界面,讓RO顯式批准。這個可以參考下一節實例化分析中的描述。

(3) Client向AS請求“訪問令牌(Access Token)”。此時,Client需向AS提供RO的“授權證據”,以及Client自己身份的憑證。

(4) AS驗證通過後,向Client返回“訪問令牌”。訪問令牌也有多種類型,若為bearer類型,那麼誰持有訪問令牌,誰就能訪問資源。

(5) Client攜帶“訪問令牌”訪問RS上的資源。在令牌的有效期內,Client可以多次攜帶令牌去訪問資源。

(6) RS驗證令牌的有效性,比如是否偽造、是否越權、是否過期,驗證通過後,才能提供服務。
2.4 授權碼類型的開放授權

[Figure 2: Authorization Code Flow]

如圖2所示,授權碼類型的開放授權協議流程描述如下:

(1) Client初始化協議的執行流程。首先通過HTTP 302來重定向RO用戶代理到AS。Client在redirect_uri中應包含如下參數:client_id, scope (描述被訪問的資源), redirect_uri (即Client的URI), state (用於抵制CSRF攻擊). 此外,請求中還可以包含access_type和approval_prompt參數。當approval_prompt=force時,AS將提供交互頁面,要求RO必須顯式地批准(或拒絕)Client的此次請求。如果沒有approval_prompt參數,則默認為RO批准此次請求。當access_type=offline時,AS將在頒發access_token時,同時還會頒發一個refresh_token。因為access_token的有效期較短(如3600秒),為了優化協議執行流程,offline方式將允許Client直接持refresh_token來換取一個新的access_token。

(2) AS認證RO身份,並提供頁面供RO決定是否批准或拒絕Client的此次請求(當approval_prompt=force時)。

(3) 若請求被批准,AS使用步驟(1)中Client提供的redirect_uri重定向RO用戶代理到Client。redirect_uri須包含authorization_code,以及步驟1中Client提供的state。若請求被拒絕,AS將通過redirect_uri返回相應的錯誤信息。

(4) Client拿authorization_code去訪問AS以交換所需的access_token。Client請求信息中應包含用於認證Client身份所需的認證數據,以及上一步請求authorization_code時所用的redirect_uri。

(5) AS在收到authorization_code時需要驗證Client的身份,並驗證收到的redirect_uri與第3步請求authorization_code時所使用的redirect_uri相匹配。如果驗證通過,AS將返回access_token,以及refresh_token(若access_type=offline)。

如果讀者對這個流程的細節不甚清楚,那麼可以先看第3節的一個實例化描述,然後再回來看這部分內容。

3. OAuth協議實例化描述

下面我以實例化方式來幫助讀者理解授權碼類型的授權協議的運行過程。假設:
(1) Alice有一個有效的Google帳號;
(2) Facebook.com已經在Google Authorization Server上注冊了Client身份,已經獲得(client_id, client_secret),注意client_secret是Client與AS之間的一個共享密鑰。
(3) Alice想授權Facebook.com查看她的聯系人列表(https://www.google.com/m8/feeds)。

圖3展示了Alice、Facebook.com、Google資源服務器、以及Google OAuth授權服務器之間的協議運行過程。


[Figure 3: An Instance of Authorization Code Flow]
//若字體無法看清,請單擊右鍵->選擇查看原圖

協議所涉及到的細節都已經在圖3上了,所以不打算再做詳細介紹了。若看懂了此圖,OAuth2.0就理解了。

讀者請注意,在步驟(4)中,Client需要拿“授權碼”去換“授權令牌”時,Client需要向AS證明自己的身份,即證明自己就是步驟(2)中Alice批准授權時的Grantee。這個身份證明的方法主要有兩種(圖3中使用了第1種):
(1) 通過https直接將client_secret發送給AS,因為client_secret是由Client與AS所共享,所以只要傳送client_secret的信道安全即可。
(2) 通過消息認證碼來認證Client身份,典型的算法有HMAC-SHA1。在這種方式下,Client無需傳送client_secret,只需發送消息請求的signature即可。由於不需要向AS傳遞敏感數據,所以它只需要使用http即可。

此外, 在步驟(2)中,Google授權服務器需要認證Alice的RO身份,並提供授權界面給Alice進行授權審批。今天Google提供的實例如圖4、圖5所示,僅供讀者理解OAuth這種“現場授權”或"在線授權"的含義。

[Figure 4: RO's Identity Authentication]


[Figure 5: RO's Authorization Decision]

4. OAuth設計上的安全性考慮

4.1 為何引入authorization_code?

協議設計中,為什麼要使用authorization_code來交換access_token?這是讀者容易想到的一個問題。也就是說,在協議的第3步,為什麼不直接將access_token通過重定向方式返回給Client呢?比如:

HTTP/1.1 302
Location:
https://www.facebook.com/?access_token=ya29.AHES6ZSXVKYTW2VAGZtnMjD&token_type=Bearer&expires_in=3600

如果直接返回access_token,協議將變得更加簡潔,而且少一次Client與AS之間的交互,性能也更優。那為何不這麼設計呢?協議文檔[1]中並沒有給出這樣設計的理由,但也不難分析:

(1) 浏覽器的redirect_uri是一個不安全信道,此方式不適合於傳遞敏感數據(如access_token)。因為uri可能通過HTTP referrer被傳遞給其它惡意站點,也可能存在於浏覽器cacher或log文件中,這就給攻擊者盜取access_token帶來了很多機會。另外,此協議也不應該假設RO用戶代理的行為是可信賴的,因為RO的浏覽器可能早已被攻擊者植入了跨站腳本用來監聽access_token。因此,access_token通過RO的用戶代理傳遞給Client,會顯著擴大access_token被洩露的風險。 但authorization_code可以通過redirect_uri方式來傳遞,是因為authorization_code並不像access_token一樣敏感。即使authorization_code被洩露,攻擊者也無法直接拿到access_token,因為拿authorization_code去交換access_token是需要驗證Client的真實身份。也就是說,除了Client之外,其他人拿authorization_code是沒有用的。 此外,access_token應該只頒發給Client使用,其他任何主體(包括RO)都不應該獲取access_token。協議的設計應能保證Client是唯一有能力獲取access_token的主體。引入authorization_code之後,便可以保證Client是access_token的唯一持有人。當然,Client也是唯一的有義務需要保護access_token不被洩露。

(2) 引入authorization_code還會帶來如下的好處。由於協議需要驗證Client的身份,如果不引入authorization_code,這個Client的身份認證只能通過第1步的redirect_uri來傳遞。同樣由於redirect_uri是一個不安全信道,這就額外要求Client必須使用數字簽名技術來進行身份認證,而不能用簡單的密碼或口令認證方式。引入authorization_code之後,AS可以直接對Client進行身份認證(見步驟4和5),而且可以支持任意的Client認證方式(比如,簡單地直接將Client端密鑰發送給AS)。

在我們理解了上述安全性考慮之後,讀者也許會有豁然開朗的感覺,懂得了引入authorization_code的妙處。那麼,是不是一定要引入authorization_code才能解決這些安全問題呢?當然不是。筆者將會在另一篇博文給出一個直接返回access_token的擴展授權類型解決方案,它在滿足相同安全性的條件下,使協議更簡潔,交互次數更少。

4.2 基於Web安全的考慮

OAuth協議設計不同於簡單的網絡安全協議的設計,因為OAuth需要考慮各種Web攻擊,比如CSRF (Cross-Site Request Forgery), XSS (Cross Site Script), Clickjacking。要理解這些攻擊原理,讀者需要對浏覽器安全(eg, Same Origin Policy, 同源策略)有基本理解。比如,在redirect_uri中引入state參數就是從浏覽器安全角度考慮的,有了它就可以抵制CSRF攻擊。如果沒有這個參數,攻擊者便可以在redirect_uri中注入攻擊者提供的authorization_code或access_token,結果可能導致Client訪問錯誤的資源(比如,將款項匯到一個錯誤的帳號)。

基於Web安全的考慮,OAuth協議文檔中已經有了比較全面的闡述,所以我不打算在此文中進行展開,有興趣的讀者請參考[1]。

5. 結語

本文對OAuth 2.0 開放授權協議及其設計上的安全性考慮做了一個基本的介紹,希望能給參與安全協議設計和開發的同學起到一點幫助。

參考文獻:

[1] Hammer-Lahav, E., Recordon, D., and D. Hardt, "The OAuth 2.0 Authorization Framework", draft-ietf-oauth-v2-31 (work in progress), June 2012.
[2] http://aws.amazon.com/iam/

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved