全面詳解互聯網企業開放API的 “守護神”

前言

這篇文章前前後後寫了兩個多禮拜,也是自己第三次寫4000字以上的技術單篇文章。寫作過程先是根據自己的思考和資料查找確認,再結合宙斯開放平臺的實際使用,每天中午吃過飯一個小時來將這些內容碎片化的記錄下來,今天得以利用整塊的時間梳理總結完成。

研究Oauth這個方向的原因,第一是我本身就在做開放平臺相關的工作,我需要對這一技術有個更深的瞭解;第二是今年618值班期間對線上開放安全的謹慎心理促使我去上網查找有關Oauth安全使用。

當時發現了一本正在預售的《Oauth2實戰》這本書,心想關於Oauth的技術居然也有人寫成了一本書,那時候第一反應是,只要有了方向就有了厚度。這也更加堅定了我深入研究這種技術的信心。

在7月初拿到這本書之後,整個7月份和8月初我都在反覆的來翻閱這本書。本文的部分內容當然也有對這本書的總結和思考。

正文開始

Oauth的歷史起源

回顧歷史,在2007年以前所有的WEB服務公司,包括現在我們已經知名的Twitter和Google等互聯網巨頭企業,這些大的互聯網公司都有很多個系統,如果用戶需要在這些系統之間無縫瀏覽,大部分都是通過一種叫做分佈式認證OpenID的方式來實現。再進一步如果他們要想讓第三方應用訪問自己的API都是利用各自的專有實現,因爲OpenID的方式只是一種認證,解決了“是不是”的問題,它無法將用戶名和密碼用於API來解決“可不可以”的問題。

爲了解決這個問題,當時一些開發人員嘗試發明一種協議,可以允許用戶對API訪問授權。期望的是讓第三方應用只要獲得用戶的授權並得的一個訪問令牌,就能使用這個令牌來訪問API。在2007年12月Oauth Core 1.0發佈,象所有的新生事物一樣,Oauth1.0也有它不完善的地方,其中就包括被發現會話固化攻擊的漏洞,直到2009年6月發佈了Oauth Core 1.0 Revision A版本徹底解決了這一問題。

在緊接着的2010年5月互聯網工程任務組(IETF)發佈了Oauth 2.0的草案。在2012年IETF最終批准了Oauth 2.0 核心規範,我們現在所有使用的Oauth技術都是基於這一規範。Oauth2.0對比Oauth1.0最大的區別,除了安全性進一步提高之外,還有一個重要本質區別,Oauth2.0是在基礎層面提供了設計規範,也就是說我們只要遵守了這種規範就可以靈活地應用到我們現實世界的各種場景。

現在Oauth2.0早已經是互聯網上首選的授權協議,無論大型互聯網企業還是初創型企業,都在廣泛的使用這一協議。

最標準的Oauth2流程

Oauth的最原始背景就是解決WEB應用下的授權的安全問題,因此一定不能缺少瀏覽器的參與。對於非標準條件下的Oauth流程在後續的文字中我們會有講述,那個時候可能有的場景是不需要瀏覽器的。現在我們在敘述的是標準場景下的Oauth使用。

Oauth組件間的通信包括前端通信和後端通信,前端通信就是組件之間的需要交互的信息數據在瀏覽器裏面流轉,後端通信就是組件之間需要交互的數據信息通過WEB SERVER之間流轉。實際上只有標準場景下的Oauth2流程纔會既使用前端通信又使用後端通信,這點在介紹非標準場景下的Oauth使用的時候也會去分析,大家先記下來。

資源所有者A要授權正在使用的第三方軟件來能夠訪問A在平臺上受保護的資源,那麼A通過瀏覽器首先訪問的是第三方軟件的URI地址,此時第三方軟件遵循Oauth2.0的協議並按照平臺的要求拼接授權URL,將用戶引導到平臺的授權頁面,這個時候發生了第一次URI重定向。

A點擊了授權頁面上的授權按鈕,平臺一方的授權服務器會對當前的用戶進行身份驗證,如果身份合法會生成一個CODE也就是我們常說的授權碼,然後將這個CODE重定向回第三方軟件的CALLBACK URI上(這個CALLBACK URI是拼接授權URI的時候就傳過來了),這個時候發生了第二次URI重定向。

第一次重定向好理解,用戶在使用瀏覽器訪問第三方軟件的URI地址,第三方軟件需要做引導。第二次重定向爲什麼也需要呢,通過WEB SERVER直接OUT PRINT回第三方軟件的服務器不就可以了嗎,如果僅僅是返回這個CODE值當然可以,而且這樣還更安全。但是不要忘記了用戶還在瀏覽器上面等着呢,如果將CODE的值直接寫回到第三方軟件的WEB SERVER上,就會把瀏覽器上的用戶旁路了,因此還必須進行第二次重定向。至此獲取CODE的流程都是通過前端通信進行交互的。

在第三方軟件獲取到CODE之後,同樣遵循Oauth2.0的協議並按照平臺的要求,會發起一個HTTP POST請求到授權服務器,去訪獲取ACCESS TOKEN(訪問令牌),這個HTTP請求中包含了平臺一方事先給第三方軟件分配好的client_id和client_secret,這樣ACCESS TOKEN的數據傳遞就是在兩個WEB SERVER之間的交互了。至此獲取訪問令牌的流程是通過後端通信進行交互的,另外再加上HTTPS的保護,ACCESS TOKEN的獲取變得更安全了。

以上交互通信如下圖所示。

我們還會思考另外一個問題,爲什麼標準流程下需要先獲取CODE,然後再通過CODE獲取ACCESS TOKEN呢?這個原因可以結合前端通信環節中的必須經過兩次瀏覽器重定向的描述,如果沒有獲取CODE這個流程,直接將ACCESS TOKEN重定向回瀏覽器,無疑這會將訪問令牌暴露出去帶來安全上的問題。

非標準的Oauth2流程

如果將授權碼的方式認定爲是標準授權流程的話,那麼除此之外的各種方式的授權流程都可以稱之爲非標準授權流程。其實支持非標準流程的授權也正是Oauth2.0的偉大之處,因爲我們構建的應用程序都是要滿足現實世界的需求,立足於各種生產實際環境的,授權當然也需要適應各種現實環境的變化。這樣的適應性也正是Oauth2.0在某些關鍵點上的靈活性體現,它提前預見了一些現實需求世界的變化。

那麼現實需求世界中非標準流程的應用都有哪些呢。

1-沒有服務器的應用

比如JavaScript應用,這種應用本身將自己嵌入到了瀏覽器內部,沒有也不需要服務端的支持。此類應用不適合使用標準的授權碼方式的Oauth2流程。根據先前介紹的授權碼流程我們得知,因爲通過CODE換取TOKEN的各個步驟中瀏覽器和應用之間的信息是隔離的,也就是說瀏覽器接觸不到由應用控制的信息,應用也不知道瀏覽器的狀態。但是當應用嵌入到瀏覽器之後,應用的所有操作和信息對瀏覽器都不再有保密性可言了,因此通過CODE這一步也就沒有實際意義了。

此類型的應用在請求授權服務器之後會直接得到一個授權碼TOKEN,官方把這種方式稱爲[隱式許可類型]。而且在換取授權碼的時候也無需傳入祕鑰secret的值,同理對於在瀏覽器中secret的值已經無處藏身了。缺少了對應用的身份認證之後,當然在這種方式下安全性會大打折扣,這是我們需要注意的事情。

2-沒有授權用戶的應用

我們知道授權的動作都由有資源的擁有者發起的,但有一種應用可能是沒有明確的資源擁有者了,或者說這個應用本身就是資源擁有者,應用和資源擁有者"合二爲一"了。這類應用一般都是原生應用。這類應用我們可以直接通過clientid和secret去換取token的方式處理授權,官方把這種方式稱爲[客戶端憑據許可]。

不過在Oauth2.0裏面,對於類似"應用就是資源擁有者"這樣的情況,也提供了可以使用Oauth流程的支持,這樣Oauth的授權流程便具有了統一性。另外還有一點區別需要我們能夠認識到,clientid和secret是解決開發者能夠調用平臺的問題,Oauth2是解決開發者可以獲取用戶數據的問題。

這種類型的應用也可以由應用自身發起CODE請求,再傳輸CODE換取TOKEN。我們可能會意識到這不是標準的授權碼流程麼,可是我們現在說的不是非標準流程的授權方式嗎。因爲在真正標準的授權碼流程中的發起方是資源擁有者而不是應用本身,先前我們也介紹了Oauth2.0兼備了這種類型應用也可以使用授權流程的統一性。這裏的非標準實際上是指發起CODE請求的不再是資源擁有者而是換成了應用。這種方式我們也可以稱爲[類授權碼許可]

小程序中的使用

1-支付寶小程序

開發者在開發小程序需要接入授權流程的時候,這種情況下仍然是需要兩個步驟,分別是獲取CODE和ACCESS_TOKEN。只不過小程序的環境下所採取的方式跟WEB環境下獲取的方式不同。以支付寶小程序舉例,如下圖所示,第一步獲取CODE的時候是通過JS API的方式調用支付寶APP的本地方法,第二步獲取ACCESS_TOKEN是通過開發者自己的服務器去請求到授權平臺,發請求的時候附帶上第一步的CODE值。

2-微信小程序

那麼微信小程序採取的授權流程又是怎樣的呢,我們到微信小程序官方文檔上去搜索會發現,微信的規範是要求開發者採用客戶端憑據的方式來獲取調用後臺接口的憑據ACCESS_TOKEN。如下截圖所示,

微信小程序的授權方式實際上是Oauth2.0多種授權方式的其中一種,叫做客戶端憑據方式。從請求參數中的授權類型這個參數可以看到grant_type的值爲client_credential。這種授權方式就沒有了授權碼CODE或者其它任何換取TOKEN的臨時憑據。

向授權服務器進行身份認證的請求參數是appid和secret,一個是應用的ID,一個是應用被分配的祕鑰。同時客戶端憑據這種授權方式中也不會有刷新令牌,因爲授權系統會認爲客戶端可以隨時獲取新令牌。

不過需要注意的一點是,微信小程序也有個授權,根據微信官方文檔可以得知wx.authorize(Object object)這個授權並沒有返回我們熟知的Oauth裏面的CODE等兌換TOKEN的憑據。

實際上這個授權是讓第三方小程序能夠獲取到微信APP裏面的功能以及手機本身的功能,比如拍照、錄音等。如果是需要發起HTTP請求調用的API是需要通過上文說的客戶端憑據的方式。

但微信給我們返回的數據都是加密的,解密的時候需要我們登錄的時候的SESSION_KEY來作爲祕鑰解密,當然每個登錄用戶的SESSION_KEY是不一致的。

Oauth面臨的安全風險

在Oauth的發展歷史上,最大的"安全風險漏洞"事件,可能是2014年被新加坡的一位大學學生髮現的了,據記載當時可謂影響了全世界的互聯網公司,騰訊、阿里巴巴、支付寶、搜狐、網易、人人網、開心網、亞馬遜、微軟、eBay、Facebook、Google、雅虎等等這些巨頭們都受到波及。但後續證明這個當時被稱爲"隱蔽重定向漏洞",並不是Oauth本身的漏洞。

實際上Oauth的使用方沒有按照Oauth的標準去接入,涉及到的上述公司均反饋是出現在他們平臺上的第三方系統,而不是公司的自有站點。這也就是剛開始我們描述安全風險漏洞的時候爲什麼加了引號,我們說那一次引起轟動的"漏洞"是沒有按照標準接入的原因正是忽略了回調URL校驗

我們來看下發生這個問題點的位置,如下圖所示。在黑色圈裏面的回調URL是開發者在入住開放平臺的時候填寫的,如果授權碼流程的第一個重定向被惡意用戶篡改了callback的值,授權服務器又沒有跟註冊時候入庫的值做校驗,在第二次重定向的時候就會把數據發送到了惡意用戶所指定的服務器上面去了。

那麼如果不按照Oauth的建議規範去接入使用,還有哪些安全風險呢,比如CSRF(跨站僞造)就是其一。讓我們一起來看下面這張圖,黑色圈這個位置就是被惡意攻擊者攻擊的位置。如果將code值僞造成一個非法的值,那麼授權服務就遭受到token暴力搜索。如果將Oauth作爲認證來使用,那更將是一個災難。

應對策略就是在第三方應用請求code的url上增加state參數,並把state的參數值保存起來,授權服務器發起重定向請求的時候再把state參數值帶過來,第三方應用會做一個state值比對判斷,如果兩個state的值不相同,則有可能發生了被僞造攻擊。

關於Oauth的安全上面只是列舉了其中一個方面,自從Oauth1.0升級到Oauth2.0之後,Oauth實際上從單體的變成了模塊化,比如有客戶端(第三方應用)、授權服務器、受保護資源,這三個模塊每一個都面臨着因使用Oauth規範不當而出現的安全風險問題。

總結

開放平臺的基礎技術需要 “兩條腿” 能夠跑起來,這兩條腿分別是網關和Oauth。網關可以讓內部的API被外部調用,Oauth可以保護這些被調用的API。Oauth是一種協議,也是一種工具。Oauth本身是屬於安全範疇的,它管理者API的訪問權限,守護者重要的數據。

本文從Oauth的起源歷史開始說起,先後介紹了Oauth的授權碼許可流程和其它非標準流程的示例,還介紹到了支付寶小程序和微信小程序中的授權。最後又介紹到了Oauth所面臨的安全風險,列舉了兩個安全風險的例子以及這種安全防範的應對措施。

reference

https://docs.alipay.com/mini/introduce/authcode 支付寶小程序授權

https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html 微信小程序授權

發佈了87 篇原創文章 · 獲贊 30 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章