OAuth2.0協(xié)議原理詳解

OAuth 2.0 是目前比較流行的做法粹懒,它率先被Google, Yahoo, Microsoft, Facebook等使用梯醒。之所以標(biāo)注為 2.0,是因為最初有一個1.0協(xié)議恨狈,但這個1.0協(xié)議被弄得太復(fù)雜吹由,易用性差,所以沒有得到普及才顿。2.0是一個新的設(shè)計莫湘,協(xié)議簡單清晰,但它并不兼容1.0娜膘,可以說與1.0沒什么關(guān)系逊脯。所以,我就只介紹2.0竣贪。

協(xié)議的參與者

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

  • RO (resource owner): 資源所有者,對資源具有授權(quán)能力的人演怎。如上文中的用戶Alice匕争。
  • RS (resource server): 資源服務(wù)器,它存儲資源爷耀,并處理對資源的訪問請求甘桑。如Google資源服務(wù)器,它所保管的資源就是用戶Alice的照片歹叮。
  • Client: 第三方應(yīng)用跑杭,它獲得RO的授權(quán)后便可以去訪問RO的資源。如網(wǎng)易印像服務(wù)咆耿。
  • AS (authorization server): 授權(quán)服務(wù)器德谅,它認(rèn)證RO的身份,為RO提供授權(quán)審批流程萨螺,并最終頒發(fā)授權(quán)令牌(Access Token)窄做。讀者請注意,為了便于協(xié)議的描述慰技,這里只是在邏輯上把AS與RS區(qū)分開來椭盏;在物理上,AS與RS的功能可以由同一個服務(wù)器來提供服務(wù)吻商。

授權(quán)類型

在開放授權(quán)中掏颊,第三方應(yīng)用(Client)可能是一個Web站點,也可能是在瀏覽器中運行的一段JavaScript代碼艾帐,還可能是安裝在本地的一個應(yīng)用程序乌叶。這些第三方應(yīng)用都有各自的安全特性改化。對于Web站點來說,它與RO瀏覽器是分離的枉昏,它可以自己保存協(xié)議中的敏感數(shù)據(jù),這些密鑰可以不暴露給RO揍鸟;對于javascript代碼和本地安全的應(yīng)用程序來說兄裂,它本來就運行在RO的瀏覽器中,RO是可以訪問到Client在協(xié)議中的敏感數(shù)據(jù)阳藻。

OAuth為了支持這些不同類型的第三方應(yīng)用晰奖,提出了多種授權(quán)類型,如:

  • 授權(quán)碼 (Authorization Code Grant)
  • 隱式授權(quán) (Implicit Grant)
  • RO憑證授權(quán) (Resource Owner Password Credentials Grant)
  • Client憑證授權(quán) (Client Credentials Grant)

由于本文旨在幫助用戶理解OAuth協(xié)議腥泥,所以我將先介紹這些授權(quán)類型的基本思路匾南,然后選擇其中最核心、最難理解蛔外、也是最廣泛使用的一種授權(quán)類型——“授權(quán)碼”蛆楞,進(jìn)行深入的介紹。

2.1 授權(quán)碼模式
mark

(A) web客戶端通過將終端用戶的user-agent重定向到授權(quán)服務(wù)器來發(fā)起這個流程夹厌”客戶端傳入它的客戶端標(biāo)識符、請求作用域矛纹、本地狀態(tài)和一個重定向URI臂聋,在訪問被許可(或被拒絕)后授權(quán)服務(wù)器會重新將終端用戶引導(dǎo)回這個URI。

(B) 授權(quán)服務(wù)器驗證終端用戶(借助于user-agent)或南,并確定終端用戶是否許可客戶端的訪問請求孩等。

(C) 假定終端用戶許可了這次訪問,授權(quán)服務(wù)器會將user-agent重定向到之前提供的重定向URI上去采够。授權(quán)服務(wù)器為客戶端傳回一個授權(quán)碼做獲取訪問令牌之用肄方。

(D) 客戶端通過驗證并傳入上一步取得的授權(quán)碼從授權(quán)服務(wù)器請求一個訪問令牌。(需要帶上ClientId和Secret吁恍,ClientId和Secret是通過平臺授予)

(E) 授權(quán)服務(wù)器驗證客戶端私有證書和授權(quán)碼的有效性并返回訪問令牌扒秸。

2.2 隱授權(quán)模式(implicit grant type)

User-Agent適用于客戶端不能保存客戶端私有證書的App(純客戶端App,無Server參與)冀瓦。因為純客戶端的程序不能保存密鑰

mark

(A) 客戶端將user-agent引導(dǎo)到終端用戶授權(quán)endpoint伴奥。客戶端傳入它的客戶端標(biāo)識符翼闽、請求作用域拾徙、本地狀態(tài)和一個重定向URI,在訪問被許可(或被拒絕)后授權(quán)服務(wù)器會重新將終端用戶引導(dǎo)回這個URI感局。

(B) 授權(quán)服務(wù)器驗證終端用戶(通過user-agent)并確認(rèn)終端用戶是許可還是拒絕了客戶端的訪問請求尼啡。

(C) 如果終端用戶許可了這次訪問暂衡,那么授權(quán)服務(wù)器會將user-agent引導(dǎo)到之前提供的重定向URI。重定向URI會在URI片斷{譯者注:URI片斷是指URI中#號之后的內(nèi)容}中包含訪問令牌崖瞭。

(D) user-agent響應(yīng)重定向指令狂巢,向web服務(wù)器發(fā)送不包含URI片斷的請求。user-agent在本地保存URI片斷书聚。

(E) web服務(wù)器返回一個web頁面(通常是嵌入了腳本的HTML網(wǎng)頁)唧领,這個頁面能夠訪問完整的重定向URI,它包含了由user-agent保存的URI片斷雌续,同時這個頁面能夠?qū)赨RI片斷中的訪問令牌(和其它參數(shù))提取出來斩个。

(F) user-agent在本地執(zhí)行由web服務(wù)器提供的腳本,該腳本提取出訪問令牌并將它傳遞給客戶端驯杜。

2.3 密碼模式

密碼模式就是將密碼托管給第三方App受啥,但是必須要保證第三方App高度可信。

mark

(A)用戶向客戶端提供用戶名和密碼鸽心。

(B)客戶端將用戶名和密碼發(fā)給認(rèn)證服務(wù)器滚局,向后者請求令牌。

(C)認(rèn)證服務(wù)器確認(rèn)無誤后再悼,向客戶端提供訪問令牌核畴。

2.4 客戶端模式

這種模式不需要終端用戶的參與,只是Client和Server端的交互冲九。通常只用于Client狀態(tài)的獲取谤草。

mark

(A)客戶端向認(rèn)證服務(wù)器進(jìn)行身份認(rèn)證,并要求一個訪問令牌莺奸。

(B)認(rèn)證服務(wù)器確認(rèn)無誤后丑孩,向客戶端提供訪問令牌。

授權(quán)碼模式的實例化描述

面我以實例化方式來幫助讀者理解授權(quán)碼類型的授權(quán)協(xié)議的運行過程灭贷。假設(shè):

(1) Alice有一個有效的Google帳號温学;

(2) Facebook.com已經(jīng)在Google Authorization Server上注冊了Client身份,已經(jīng)獲得(client_id, client_secret)甚疟,注意client_secret是Client與AS之間的一個共享密鑰仗岖。

(3) Alice想授權(quán)Facebook.com查看她的聯(lián)系人列表(https://www.google.com/m8/feeds)。

下圖展示了Alice览妖、Facebook.com轧拄、Google資源服務(wù)器、以及Google OAuth授權(quán)服務(wù)器之間的協(xié)議運行過程讽膏。


mark

協(xié)議所涉及到的細(xì)節(jié)都已經(jīng)在圖上了檩电,所以不打算再做詳細(xì)介紹了。若看懂了此圖,OAuth2.0就理解了俐末。

讀者請注意料按,在步驟(4)中,Client需要拿“授權(quán)碼”去換“授權(quán)令牌”時卓箫,Client需要向AS證明自己的身份载矿,即證明自己就是步驟(2)中Alice批準(zhǔn)授權(quán)時的Grantee。這個身份證明的方法主要有兩種(圖3中使用了第1種):

(1) 通過https直接將client_secret發(fā)送給AS烹卒,因為client_secret是由Client與AS所共享恢准,所以只要傳送client_secret的信道安全即可。

(2) 通過消息認(rèn)證碼來認(rèn)證Client身份甫题,典型的算法有HMAC-SHA1。在這種方式下涂召,Client無需傳送client_secret坠非,只需發(fā)送消息請求的signature即可。由于不需要向AS傳遞敏感數(shù)據(jù)果正,所以它只需要使用http即可炎码。

此外, 在步驟(2)中秋泳,Google授權(quán)服務(wù)器需要認(rèn)證Alice的RO身份潦闲,并提供授權(quán)界面給Alice進(jìn)行授權(quán)審批。今天Google提供的實例如下圖所示迫皱,僅供讀者理解OAuth這種“現(xiàn)場授權(quán)”或"在線授權(quán)"的含義歉闰。


mark
mark

OAuth2.0授權(quán)類型選擇

授權(quán)模式實際上就是指獲取token的方法,選擇授權(quán)模式主要取決于最終用戶使用的客戶端的類型卓起,以及你服務(wù)對用戶的表現(xiàn)形式和敬。

具體的選擇方式如下圖:

mark
First Party or third party client?

First party指的是,你完全信任這個客戶端可以管理好最終用戶的認(rèn)證憑據(jù)戏阅。比如說對于Spotify的開發(fā)者和所有者來說昼弟,他們完全信任他們的Spotify iphone客戶端。而third party客戶端是指我們不信任的客戶端奕筐。

Access Token Owner舱痘?

Access Token表示給一個客戶端授權(quán)訪問某些被保護(hù)的資源。如果我們只需要給一個機(jī)器授權(quán)訪問某些資源离赫,而不需要給人授權(quán)芭逝,那么這些資源應(yīng)該實現(xiàn)client credential grant。

如果我們需要給人授權(quán)訪問資源笆怠,那么需要視客戶端的類型做決定铝耻。

Client type?

客戶端類型主要是指客戶端是否有能力保存秘鑰。

如果客戶端是個web app,并且有服務(wù)器側(cè)的組件瓢捉,那么我們應(yīng)該選擇authorization code grant

如果客戶端是一個純前端的web app(如:單頁面應(yīng)用),如果客戶端可信频丘,我們可以選擇password grant,如果客戶端不可信可以選擇implicit grant

如果客戶端是一個本地應(yīng)用泡态,比如一個手機(jī)app搂漠,應(yīng)該選擇password grant。

第三方本地應(yīng)用應(yīng)該用authorization code grant(通過本地瀏覽器某弦,不要用嵌入式瀏覽器桐汤,比如iOS強(qiáng)制用戶用Safari或者SFSafariViewController,而不用 WKWebView)靶壮。

OAuth設(shè)計上的安全性考慮

為何引入authorization_code怔毛?

協(xié)議設(shè)計中,為什么要使用authorization_code來交換access_token腾降?這是讀者容易想到的一個問題拣度。也就是說,在協(xié)議的第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,協(xié)議將變得更加簡潔奸晴,而且少一次Client與AS之間的交互冤馏,性能也更優(yōu)。那為何不這么設(shè)計呢寄啼?協(xié)議文檔[1]中并沒有給出這樣設(shè)計的理由逮光,但也不難分析:

(1) 瀏覽器的redirect_uri是一個不安全信道,此方式不適合于傳遞敏感數(shù)據(jù)(如access_token)墩划。因為uri可能通過HTTP referrer被傳遞給其它惡意站點睦霎,也可能存在于瀏覽器cacher或log文件中,這就給攻擊者盜取access_token帶來了很多機(jī)會走诞。另外副女,此協(xié)議也不應(yīng)該假設(shè)RO用戶代理的行為是可信賴的,因為RO的瀏覽器可能早已被攻擊者植入了跨站腳本用來監(jiān)聽access_token蚣旱。因此碑幅,access_token通過RO的用戶代理傳遞給Client,會顯著擴(kuò)大access_token被泄露的風(fēng)險塞绿。 但authorization_code可以通過redirect_uri方式來傳遞沟涨,是因為authorization_code并不像access_token一樣敏感。即使authorization_code被泄露异吻,攻擊者也無法直接拿到access_token裹赴,因為拿authorization_code去交換access_token是需要驗證Client的真實身份喜庞。也就是說,除了Client之外棋返,其他人拿authorization_code是沒有用的延都。 此外,access_token應(yīng)該只頒發(fā)給Client使用睛竣,其他任何主體(包括RO)都不應(yīng)該獲取access_token晰房。協(xié)議的設(shè)計應(yīng)能保證Client是唯一有能力獲取access_token的主體。引入authorization_code之后射沟,便可以保證Client是access_token的唯一持有人殊者。當(dāng)然,Client也是唯一的有義務(wù)需要保護(hù)access_token不被泄露验夯。

(2) 引入authorization_code還會帶來如下的好處猖吴。由于協(xié)議需要驗證Client的身份,如果不引入authorization_code挥转,這個Client的身份認(rèn)證只能通過第1步的redirect_uri來傳遞距误。同樣由于redirect_uri是一個不安全信道,這就額外要求Client必須使用數(shù)字簽名技術(shù)

來進(jìn)行身份認(rèn)證扁位,而不能用簡單的密碼或口令認(rèn)證方式。引入authorization_code之后趁俊,AS可以直接對Client進(jìn)行身份認(rèn)證(見步驟4和5)域仇,而且可以支持任意的Client認(rèn)證方式(比如,簡單地直接將Client端密鑰發(fā)送給AS)寺擂。

在我們理解了上述安全性考慮之后暇务,讀者也許會有豁然開朗的感覺,懂得了引入authorization_code的妙處怔软。那么垦细,是不是一定要引入authorization_code才能解決這些安全問題呢?當(dāng)然不是挡逼。筆者將會在另一篇博文給出一個直接返回access_token的擴(kuò)展授權(quán)類型解決方案括改,它在滿足相同安全性的條件下,使協(xié)議更簡潔家坎,交互次數(shù)更少嘱能。

一切只是看上去很美好,但其實很多坑

OAuth2看上去很美好虱疏,但是細(xì)心觀察其實還是有一些漏洞的惹骂。

對于授權(quán)碼和access_token的篡改,在OAuth1中是反復(fù)的對Code和Token進(jìn)行簽名做瞪,來保證Token不會被篡改对粪,但是OAuth2中卻沒有,因為OAuth2是基于Https的,所以如果沒有Https的支持OAuth2可能還不如OAuth1.

對于redirect_uri的校驗著拭,OAuth1中沒有提到redirect_uri的校驗纱扭,那么OAuth2中要求進(jìn)行redirect_uri的校驗。但是如果校驗規(guī)則過松茫死,也會導(dǎo)致跳轉(zhuǎn)的安全問題跪但。 例如:校驗的時候只校驗根域名,或者二級域名峦萎,但是第三方App對自己的域名保護(hù)的不好屡久,導(dǎo)致二級域名被hack那么此時授權(quán)碼和Token會被竊取。 校驗規(guī)則不嚴(yán)謹(jǐn)爱榔,例如www.baidu.com 但是redirect_uri為:www.a.com.\www.baidu.com被环,這樣授權(quán)就被a.com釣走了。

對于CSRF攻擊(跨站請求偽造):由于這個授權(quán)過程服務(wù)器和Client和用戶之間有幾次交互详幽,但是在得到授權(quán)碼的時候需要一次回跳筛欢,但是這次回跳是可以被阻塞的。

攻擊者使用自己的賬戶申請第三方授權(quán)登陸

授權(quán)后服務(wù)端返回授權(quán)碼唇聘,但是此時組織授權(quán)回跳版姑,此時Client并沒有接到授權(quán)碼,也就是阻斷了授權(quán)流程

攻擊者將此跳轉(zhuǎn)鏈接發(fā)給一個正在處于在Client登陸狀態(tài)的賬戶

誘騙正常用戶點擊迟郎,那么此時攻擊者第三方賬戶和被攻擊賬戶進(jìn)行綁定(相當(dāng)于賬戶綁定了第三方的賬戶)

攻擊者再次進(jìn)行第三方授權(quán)登陸剥险。這樣就劫持了誘騙的賬戶。轉(zhuǎn)賬宪肖?刪好友表制?等等就所以搞了。

解決辦法:

在進(jìn)行授權(quán)碼申請或者是Token申請的時候帶上state參數(shù)控乾,服務(wù)器返回請求時要求攜帶state參數(shù)么介,在Client處理授權(quán)的時候校驗此參數(shù)。參數(shù)可以是當(dāng)前賬戶的SessionId蜕衡,或Cookie的簽名串壤短。在Client申請accessToken會驗證相關(guān)state和當(dāng)前用戶的關(guān)系,這樣就防止了篡改慨仿。

OAuth的校驗流程為什么這么復(fù)雜鸽扁,直接授權(quán)之后redirect回accessToken不就結(jié)了嗎?為什么還要返回auth_code之后請求accessToken镶骗?

首先桶现,redirect是不安全的,隨時可以暫投︽ⅲ回調(diào)而拿到accessToken骡和,拿到了accessToken也就意味著拿到了授權(quán)相赁,但是auth_code是和client相對應(yīng)的,那么即使拿到了auth_code還需要再次申請accessToken慰于,申請accessToken時需要校驗Client和state钮科。同時協(xié)議設(shè)計的原則就是只有Client能拿到accessToken而用戶是拿不到的。

最后婆赠,切記HTTPS

參考資料:
http://blog.csdn.net/seccloud/article/details/8192707
http://www.justwinit.cn/post/8138/
https://blog.yorkxin.org/2013/09/30/oauth2-1-introduction
人人網(wǎng)OAuth歷程:http://www.infoq.com/cn/presentations/dx-renren-authentication-authorization/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绵脯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子休里,更是在濱河造成了極大的恐慌蛆挫,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妙黍,死亡現(xiàn)場離奇詭異悴侵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拭嫁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門可免,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人做粤,你說我怎么就攤上這事浇借。” “怎么了怕品?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵妇垢,是天一觀的道長。 經(jīng)常有香客問我堵泽,道長,這世上最難降的妖魔是什么恢总? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任迎罗,我火速辦了婚禮,結(jié)果婚禮上片仿,老公的妹妹穿的比我還像新娘纹安。我一直安慰自己,他們只是感情好砂豌,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布厢岂。 她就那樣靜靜地躺著,像睡著了一般阳距。 火紅的嫁衣襯著肌膚如雪塔粒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天筐摘,我揣著相機(jī)與錄音卒茬,去河邊找鬼船老。 笑死,一個胖子當(dāng)著我的面吹牛圃酵,可吹牛的內(nèi)容都是我干的柳畔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼郭赐,長吁一口氣:“原來是場噩夢啊……” “哼薪韩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起捌锭,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤俘陷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后舀锨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岭洲,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年坎匿,在試婚紗的時候發(fā)現(xiàn)自己被綠了盾剩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡替蔬,死狀恐怖告私,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情承桥,我是刑警寧澤驻粟,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站凶异,受9級特大地震影響蜀撑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剩彬,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一酷麦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喉恋,春花似錦沃饶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至氓鄙,卻和暖如春馆揉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抖拦。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工把介, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留勤讽,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓拗踢,卻偏偏與公主長得像脚牍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子巢墅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容