出處:http://www.cnblogs.com/neutra/archive/2012/07/26/2609300.htmlhtml
最近在作第三方接入的,初步定下使用OAuth2協議,花了些時間對OAuth2的受權方式作了些瞭解。前端
我還記得一兩年前,跟一位同事聊起互聯網時,當時我說過一個想法:算法
目前很多較爲稀有的資源,不少都是論壇提供下載的,論壇提供的下載每每要求一個論壇賬號,更有甚者,需回帖纔可見,又或者下載須要消耗必定的虛擬貨幣,而這些貨幣能夠用論壇活躍度而得到。假設如今我是一個普通用戶,我要找某個資源。經過搜索引擎或者資料,我發如今某個論壇有這個資源下載,從其餘地方得到這個資源代價比較高或者說根本就找不着。當我準備下載時,極可能就被提示需登陸後纔可下載,隨機被跳轉到註冊頁面。後端
爲了這個資源註冊一個賬號?我想,不管誰在99%的狀況下都不樂意去註冊一個只是用一次的賬號,恰恰有些論壇就是爲了某些緣由要求你必須提供一個賬號。好吧,像我這樣的人,固然是瞎填點信息註冊個賬號了事。至於註冊了賬號需不須要金幣或者多少聲望才能回帖下載之類的,這裏就不嘮叨了。這個過程的關鍵點是:我爲了一個臨時性的須要,註冊了一個永久性無關痛癢的賬號,這個賬號使用一次以後,基本上失去價值了。有無數無聊的用戶花了N多的時間在M多的論壇裏註冊了N*M個無用賬號,這個過程除了對某些統計指標有利之外,對用戶沒有任何價值。瀏覽器
可不能夠作一個平臺,使任意用戶能夠在任意論壇註冊一個賬號,隨後這個賬號和密碼自動登記到這個平臺中做爲公共賬號,以後,其餘用戶再訪問這個論壇時,就無需再次註冊賬號了,直接在這個平臺上,自動地使用公共賬號去作該作的事。這樣,隨着用戶數的增長,最終能夠達到一個比較理想的狀況:大部分論壇的臨時性操做,用戶都不用再去註冊了,也不用擔憂本身的經常使用賬號密碼等信息泄漏的問題。儘管對於一些有「經濟系統」的論壇(須要經過活躍度/發帖數/現金等有償得到虛擬貨幣,存在消費行爲),這個平臺可能不適合,但即便需求只被解決了一半,也是個有價值的產品。安全
當時只是大概聊了下,徹底沒有動手的打算,至今我還沒發現相似的產品,不知是這個需求不夠大衆仍是什麼。那時我也大概看了下OpenID,跟個人設想不同,OpenID是將一個用戶在某個平臺上的賬號,公開給其餘網站使用,固然公開的只是賬號而不會包含密碼。當時宣傳的口號大概是這樣的:「一次登陸,處處使用」。當時我只在豌豆網註冊了一個OpenID試着玩玩,感受支持這個OpenID的資源網站太少了,那個賬號做用不大。cookie
OAuth最近幾年大行其道,很大程度得益於微博的推廣。OAuth和OpenID是比較容易混淆的兩個東西,比較「官方」的觀點認爲:OpenID設計目的是「身份校驗」;OAuth的設計目的是「受權」。我也比較認同這個觀點,但我以爲這種說法自己也挺容易混淆,有位同事說「身份校驗」自己就是對「用戶資源」權限的授予,因此OAuth包含了OpenID的做用。session
在說明個人觀點以前,不妨思考下,目前提供OAuth的網站有那些,他們的提供的服務是什麼,爲何他們大多都提供OAuth卻鮮有說起OpenID?(我不是暗指騰訊啦)。網站
先看看OpenID,前面多少也講過了,下面以豌豆網爲例:搜索引擎
再來對比OAuth,用新浪微博爲例吧:
一對比,區別就很明顯了:OAuth和OpenID的區別主要是服務提供方是否提供有價值的資源。
做爲一個擁有資源的服務提供方,固然但願本身管理本身的用戶信息。假如新浪微博支持其餘網站的OpenID登陸,因爲有很多的OpenID服務提供方,那麼它須要如何管理本身的用戶呢?例如,用戶A經過網站X的OpenID登陸新浪微博,跟用戶A經過網站Y的OpenID登陸新浪微博,最終的效果是一個賬號仍是兩個賬號呢?若是用戶A在新浪微博自己有一個賬號的話,狀況又更復雜了。要麼全部賬號都按新賬號處理,要麼提供多個賬號關聯功能。前一種方案簡單易行,但產生了大量非活躍賬號,用戶體驗也不見得好。後一種方案,想想都以爲,維護是個災難。因而,大多數的資源提供方都傾向與本身管理本身的用戶信息,對於第三方的接入,開放一些受權給他們參與一些用戶資源的訪問就是了,因而便提供OAuth服務而不是提供OpenID接入,一些網站如騰訊還在 OAuth上提供了OpenID。寫着寫着,我本身都以爲OpenID的「接入」和"服務"很拗口。好吧,OpenID的接入是說使用其餘網站所驗證的賬號信息,OpenID的服務是指對外提供OpenID的身份校驗服務。
把上面的狀況循環循環再循環,最終,一方面,擁有有價值資源的網站,都作OAuth去了,他們在等待開發者和其餘第三方網站的接入,壯大他們的平臺;另外一方面,提供OpenID服務的小網站,幾乎沒有大網站的接入支持,對用戶的吸引力愈來愈小,典型的惡性循環。而後,大部分網站的OAuth服務雖然基本是按照官網規範作接口,但很多細節都作了個性化。例如部分網站的expires_in單位是秒,部分是用分作單位的。部分網站支持state做爲狀態傳遞,部分又不支持。最終這些非標準的東西,會惹惱苦逼的開發者(爲何我會很天然的想起IE?),相信不少開發者都會根據市場份額去選擇幾個流行的OAuth提供方進行兼容,其餘的,見喬布斯去吧。而用戶則會根據應用的數量去選擇平臺,又一個惡性循環。若是你的資源不夠吸引開發者,就不會有人願意爲你的自定義標準買單。莫非這就是傳說中的,合久必分分久必合?嗯,扯遠了。
我並無貶OpenID褒OAuth的意思,只是以爲在目前市場下,不太可能有大網站願意放棄提供OAuth服務而使用OpenID接入外部賬號。其實我對OpenID瞭解很少,寫着寫着,沒想到居然寫了一大坨,我真懷疑本身是否是話癆…… 有點晚,明晚繼續,if有空的話。
OAuth2是從OAuth發展而來的,雖然不向下兼容,但瞭解OAuth能更好的理解OAuth2的一些改變。
OAuth裏存在三個主要角色:用戶、服務提供方和服務消費方。很多文檔會把服務消費方說成是客戶端,對於SP來講,這個說法沒什麼問題,但我感受這個說放容易引發混淆,因此我這裏仍是用服務消費方來描述。按流行的口號,服務提供方通常對外宣稱本身是某某某開放平臺,而服務消費方則是各類第三方應用。用戶在平臺上有一些已有資源,如好友關係,照片等。
幾乎全部的OAuth平臺都有相似的背景:他們原先積累了一大堆的真實用戶,在互聯網開放的趨勢下,主動或被動的須要支持第三方應用的接入。第三方應用爲了使其功能更加豐富完整,但願從平臺能獲取甚至操做當前用戶的資源。用戶極可能不但願第三方得知他原有的賬號和密碼,緣由很明顯,安全考慮嘛。服務提供方也不但願第三方直接使用用戶的賬號和密碼登陸平臺操做用戶數據,爲啥?不便於數據統計和維護嘛,但願對 哪一個第三方操做哪一個用戶數據 和 哪一個用戶操做本身的數據 兩種處理流程有所區別。第三方很無辜,常常大喊「我覺不會使用任何途徑存儲用戶的賬號!」。即便真有人相信這些誓言,但也很難確保第三方使用賬號敏感數據時,不被第四方所捕獲,因此,認真你就輸了。
爲了解決上面的問題,準確的說是讓三種角色互相信任,OAuth由此而生。在沒有第三方的狀況下,服務提供方和用戶能夠認爲是互相信任的,由於用戶用域名來確保本身訪問的是一個受信的站點;服務提供方則要求用戶登陸,而且登陸會話能夠控制。
應爲第三方通常是不知名的,用戶很難區分第三方合不合法,因此用戶須要經過服務提供方來證明第三方,例如位於服務提供方的OAuth受權頁面會簡單的介紹該應用的簡單介紹,正是這些介紹使得用戶能夠相信,該應用是一個合法登記的第三方。
爲了讓服務提供方信任第三方應用,第三方應用在必要時須要向服務提供方提供身份憑據。最簡單的辦法就是第三方開發者去服務提供方那去註冊個賬號,而後在須要時用這個賬號來證實本身的身份。這種第三方應用的賬號,下面統稱應用賬號。因爲第三方的請求不會有人工的干預,因此應用賬號的賬號密碼通常由服務提供商提供,方便服務提供方管理,安全係數也較高,由於服務提供方能夠制定規則,使密碼更難以僞造或猜想。
按理說,第三方應用除了到SP處申請一個應用賬號外,也有其餘辦法證明本身的身份。
例如可使用HTTPS鏈接,讓「第四方」去證實。OAuth2使用的就是HTTPS鏈接,但也僅僅是服務端認證,客戶端並不作保證。估計一個方面的緣由是,應用的數量不少,通常都是中小規模開發商開發的,客戶端也要認證的話,證書申請門檻較高,一個帳號密碼能夠解決的問題有必要去申請證書嗎?另外一方面是,不少應用是沒有服務端的,使用雙向HTTPS認證無疑將這些應用拒之門外。
上面的方法是,用戶經過服務提供方,去識別第三方是否合法。還有種方式是:服務提供方經過用戶,去識別第三方是否合法。但OAuth裏沒有這種方式的體現,但OAuth2裏有相似的方式,那就是提供用戶的賬號密碼換取AccessToken,名字應該叫「資源全部者密碼憑據」。若是第三方應用只是開發者自娛自樂的小應用,這種方式是最簡單的。
通過上面的註冊和受權流程,用戶和服務提供方均可以確認第三方應用的身份了,那第三方如何確認服務提供方和用戶的身份?
第三方應用怎麼確認服務提供方的身份呢?很簡單,域名就是服務提供方的惟一標識,只要DNS不被劫持的話。第三方應用根據服務提供方的返回內容確認用戶身份,載體是操做令牌AccessToken,爲了方便後面統稱ATOK,在OAuth裏,ATOK的有效期是從用戶受權成功,到用戶取消受權,對第三方來講,幾乎是永久的。至於用戶受權以後取消受權,再受權的時候,兩次ATOK是否同樣,第三方可否處理好這種狀況,OAuth裏沒有說起,看實現者的心情了。
把上面所說的綜合在一塊兒,能夠獲得一個OAuth的雛形版本:
第三方到服務提供方註冊個應用賬號,當須要操做用戶在服務提供方處的數據時,提供應用賬號密碼申請受權,服務提供方將用戶引導到受權頁面,當受權成功時,服務提供方將對應該用戶的ATOK發給應用,隨後應用就使用這個ATOK來操做用戶數據。
下面新浪微博OAuth的基本流程(其實各平臺的流程都同樣,貼這個是以爲這張圖比較好看):
從圖中能夠看到OAuth的流程比原先設想的雛形多了很多東西,這些多出來的有什麼做用呢?
OAuth受權分四步:
第一步,應用向服務提供方申請請求令牌(Request Token),服務提供方驗證經過後將令牌返回。這個步驟因爲涉及到應用賬號密碼,在應用的服務端發起,因此這個步驟對用戶透明。
第二步,應用使用請求令牌讓瀏覽器重定向到服務提供方進行登陸驗證和受權。服務提供方校驗請求令牌,將第三方的資料顯示給用戶,提示用戶選擇贊成或拒絕這次受權。若是用戶贊成受權,發放已受權令牌並將用戶引導到當前應用的註冊地址。這個步驟從重定向開始到引導回註冊地址以前,應用方並不參與用戶身份校驗和受權過程,確保第三方不可得到用戶的真實賬號密碼。
第三步,用已受權令牌向服務提供方換取ATOK。第三方應用需在服務端發起請求,用賬號密碼和上一步的令牌換取ATOK,這個步驟對用戶而言也是透明的。若是前兩步分別是讓服務提供方認證應用和用戶,那這步就是用戶和服務提供方再次認證第三方應用。由於用戶瀏覽器將第二步的結果重定向到第三步,除非用戶DNS被劫持,不然就能確保重定向到的是合法的地址。曾經我很困惑在用戶受權以後爲什麼不直接返回ATOK而須要再次換取,估計是出於對ATOK的安全考慮,用戶瀏覽器一端存在太多的可能性讓ATOK泄漏,最安全的辦法仍是讓第三方服務端來獲取和保管ATOK。
第四步,用ATOK做爲令牌訪問受保護資源。不少時候,權限是有多種類別的。ATOK包含了某個用戶對某個應用的受權憑據,準確的說,ATOK對應用戶受權時所賦予的一系列權限的集合。因此在這一步,除了校驗ATOK的合法性以外,服務提供方還需對該ATOK是否擁有足夠的權限執行被保護操做進行判斷。
在OAuth裏,OAuth的相關請求都要作單次簽名,目的是防止OAuth的請求被篡改和重放。簽名固然是拿應用賬號的密碼來作簽名,其實就是對HTTP請求中全部OAuth相關的參數都連在一塊,使用密碼計算某種哈希值做爲簽名。OAuth規範裏描述了簽名的規則,那是至關的繁瑣、複雜,足以嚇跑一大堆未經世事的開發者。隨便找一個OAuth開放平臺的API文檔,我相信在OAuth受權流程有接近一半會在描述怎麼產生簽名構造一個合法的HTTP請求。有一對文字圖片描述還不夠,各開放平臺幾乎無一例外地提供各類開發語言下的SDK,爲求儘可能下降技術門檻。即便如此,很多開發者依然以爲,OAuth的簽名過程實在是太複雜了,而這些複雜也沒有帶來預期的好處。
爲了防止有攻擊者僞造重定向地址騙取用戶受權,服務提供方應對受權時的重定向地址進行驗證。因此註冊時,第三方應提供重定向地址。服務提供方能夠直接對重定向地址進行等值判斷,但這樣的話就沒辦法讓第三方在受權過程當中傳遞狀態,只能藉助Cookie/Session之類的方式了。服務提供方也能夠判斷重定向地址是否同一個域,這樣的話應用方就能夠在URI裏傳遞少許狀態。對於一些沒有服務端的第三方Web應用,因爲代碼是公開的,將應用的賬號密碼存在頁面裏並不合適。OAuth則建議不使用重定向地址,讓用戶在受權後,把受權碼人工輸入到應用中進行下一步。記得有段時間FaWave也是這麼添加新賬號的。
OAuth曾爆了一個安全漏洞,攻擊者利用此漏洞可騙取用戶信任獲取非法的受權。
這個網頁有該漏洞的詳細說明,流程以下:
簡單的說,這個漏洞主要的關鍵是:
1. 部分服務提供方並未對重定向地址進行合法性判斷,或者部分第三方的重定向地址會根據URI的參數再次重定向從而被攻擊者利用;
2. RequestToken從未受權到已受權的狀態轉變時沒有變化,從而爲攻擊者暴力訪問回調地址騙取ATOK提供可能;
對於第一點,攻擊者僞造重定向地址,便可騙得用戶對可靠第三方的受權,得到ATOK
對於第二點,假如第一點不成立,那攻擊者能夠用第一步的請求令牌構造一個合法的重定向請求,並在用戶受權以後、瀏覽器重定向到合法重定向地址以前,進行一樣操做執行這個重定向操做,此時就看攻擊者和正常受權流程就存在競爭關係。若是第三方先處理攻擊者的請求,攻擊者就得到了最終的ATOK。
爲了解決上述安全漏洞,OAuth更新了1.0a版本,主要改變就是第一步增長對重定向地址的簽名,和第二步與第三步之間增長一個隨機校驗碼,使之與未受權的RequestToken有所區分。
目前大部分的平臺都轉到了OAuth2。OAuth2雖並不兼容OAuth1,但基本原理是同樣的。
OAuth2對比OAuth1,主要改變有下面幾點:
1. 取消繁瑣的簽名,所有改用HTTPS。
2. ATOK從原來的永久令牌變爲臨時令牌,增長RefreshToken
3. 取消獲取RequestToken的步驟
4. 提供了多種場景的受權流程
OAuth原有的簽名算法實在是太繁瑣了,嚇跑了很多開發者。對於服務提供方,也很很差實現,特別是單次簽名的實現,因爲服務提供方要確保每次由客戶端生成的隨機碼不被重複利用,必須存儲每次請求發來的隨機碼,不管是對存儲仍是校驗都是一個難題。一般的作法是,存儲一段時間的隨機碼,這個時間需比RequestToken的過時時間要長。這樣即便到時還有重放攻擊,RequestToken也已經失效。
OAuth2取消了簽名,改用HTTPS來加密,確保通訊內容不被第三方竊取。這個改變毫無疑問是下降了門檻,受權的流程被簡化了。雖有少許人有異議,但OAuth2最大的異議是臨時的ATOK。
因爲第三方應用每每不重視ATOK的安全性,開發者爲圖方便常常把ATOK從後端發給前端頁面或者存在cookie中。因爲OAuth1中ATOK幾乎是永久性的,即便發現ATOK被盜用,也只能讓用戶取消受權,這可能會形成一些其餘的問題。OAuth2將ATOK改成臨時令牌,當ATOK過時後,須要使用RefreshToken從新獲取新的ATOK,讓開發者鬱悶的是,RefreshToken也不是永久性的,不一樣的服務提供方有不一樣的過時時間,相同的是,過時時間都不會太長,頂多也就幾個月。
這個改變對不少第三方應用是個坑爹的改變,本來他們幾乎都是拿ATOK做爲OpenID來使用的(因此纔有了各類ATOK被盜用的隱患),而到了OAuth2,ATOK已經不能惟一標識一個用戶了,他們要多作不少的東西才能維持用戶的身份,在使用ATOK訪問用戶資源時,步驟也是異常繁瑣。
雖然臨時ATOK這個改變很合理,但對開發者很不友好,從此會不會繼續改變,能夠拭目以待。我我的以爲,這個問題實際上是另一個問題,那就是開發者對用戶賬號信息的安全意識太單薄,後面講OAuth的問題時再詳細討論。
OAuth1流程比較複雜,儘管規範裏有對多種場景的受權流程進行不一樣的建議,但不少應用和開放平臺最終都使用了同一種受權流程,結果產生了安全隱患(例如上面重定向地址的問題嗎)。OAuth2描述了四種受權場景,爲這些場景下的受權流程提供指導。我只簡單說些要點和差別,詳細的說明仍是看官方文檔和各開放平臺的文檔穩妥些。