本文提取出OAuth2.0規範RFC6749的主要內容,部份內容從文檔複製出來,給你們講講第三方受權背後的故事。html
先是舉個知乎的QQ登陸受權的例子,而後講四種受權方式,兩種令牌,接着是看看協議流程,分析知乎的QQ登陸受權請求響應報文解釋OAuth2.0協議,最後簡單看看QQ提供第三方受權的API加深理解。java
先打個預防針,在講解四種受權,兩種令牌時你們可能會有點不懂,可是跟隨着協議流程走就懂了。 git
若是以爲排版很差,能夠訪問個人博客。TATgithub
http://blog.bensonlin.me/post/oauth2api
若是以爲寫得不錯,歡迎推薦,關注我和follow個人github(blog.bensonlin.me上有顯示)。瀏覽器
2016/06/18發現有人未經贊成複製個人文章到網站上,這裏表示抗議,網站以下:安全
http://www.07net01.com/2016/06/1578637.html服務器
http://***/article/150992cookie
下面是正文 工具
Open Authorization的縮寫,即開放受權協議
OAuth 的受權使應用無需涉及另外一方應用的賬號信息(如用戶名與密碼),只須要經過受權就能夠另外一方應用的信息,保證了安全性,不會泄露用戶名密碼。
而整個流程要怎麼作才能保證安全呢,該協議定義了規則。
更多的定義能夠本身查看OAuth的維基百科
第一步:固然是上知乎官網登陸,點擊QQ頭像做爲QQ登陸
圖1
第二步:登陸QQ並受權,能夠看到右邊是QQ受權給知乎的內容,獲取咱們的暱稱,頭像和性別等信息。輸入用戶名密碼登陸,能夠看到按鈕顯示的是登陸並受權,也就是是點擊後就已經說明咱們贊成讓知乎獲取咱們的這些我的信息。
圖2
由於我已經登陸了,因此直接點上面的QQ頭像(頭像就是多啦A夢)直接受權。
圖3
第三步:登陸受權成功,能夠在知乎的首頁看到你的信息(還須要補充知乎的我的信息做爲新用戶註冊)
圖4
注意:有的網站受權,是先登陸後,進入另外一個頁面而後再點擊受權的。
PS:記住圖的編號,後面分析用到
下面將進入正題,首先是上面涉及的幾個角色,而後是協議流程等
前提:知乎要用QQ登陸,使用QQ的頭像和暱稱:
還有一個角色是資源全部者的用戶代理(User Agent),通常就是咱們的Web瀏覽器,咱們須要瀏覽器做爲代理纔可以進行操做
本規範定義了四種許可類型——受權碼、隱式許可、資源全部者密碼憑據和客戶端憑據——以及用於定義其餘類型的可擴展性機制。其中受權碼是咱們最經常使用的,所以單獨講受權碼方式,其它類型詳情能夠自行下載RFC6749文檔查看,下載地址在這裏,搜索本身想要的文檔,而後右鍵另存爲下載便可
能夠看到,受權碼模式(authorization code)是功能最完整、流程最嚴密的受權模式。
+----------+ | Resource | | Owner | | | +----------+ ^ | (B) +----|-----+ Client Identifier +---------------+ | -+----(A)-- & Redirection URI ----> | | | User- | | Authorization | | Agent -+----(B)-- User authenticates ---> | Server | | | | | | -+----(C)-- Authorization Code ---< | | +-|----|---+ +---------------+ | | ^ v (A) (C) | | | | | | ^ v | | +---------+ | | | |>---(D)-- Authorization Code ----------' | | Client | & Redirection URI | | | | | |<---(E)----- Access Token --------------------' +---------+ (w/ Optional Refresh Token)
(A)客戶端經過向受權端點引導資源全部者的用戶代理開始流程。客戶端包括它的客戶端標識、請求範圍、本地狀態和重定向 URI,一旦訪問被許可(或拒絕)受權服務器將傳送用戶代理回到該URI。
(B)受權服務器驗證資源擁有者的身份(經過用戶代理),並肯定資源全部者是否授予或拒絕客戶端的訪問請求。
(C)假設資源全部者許可訪問,受權服務器使用以前(在請求時或客戶端註冊時)提供的重定向URI重定向用戶代理回到客戶端。重定向 URI 包括受權碼和以前客戶端提供的任何本地狀態。
(D)客戶端經過包含上一步中收到的受權碼從受權服務器的令牌端點請求訪問令牌。當發起請求時,客戶端與受權服務器進行身份驗證。客戶端包含用於得到受權碼的重定向 URI 來用於驗證。
(E)受權服務器對客戶端進行身份驗證,驗證受權代碼,並確保接收的重定向 URI 與在步驟(C)中用於重定向客戶端的 URI 相匹配。若是經過,受權服務器響應返回訪問令牌與可選的刷新令牌(若是原來的訪問令牌過時了,而受權服務器又容許發送新的令牌,就會攜帶過去)
其餘的協議流程能夠查看RFC文檔
注意結合上面的協議流程看分析:
爲何要分紅兩點呢?由於第一點咱們能夠容易的抓取請求響應報文獲得,而獲取訪問令牌的過程對資源全部者(咱們用戶)是透明的,也就是說咱們不會看到訪問令牌,只有知乎服務器獲得了訪問令牌;其實看不到也不該該讓資源全部者看到,不然就不安全了,由於誰均可以用訪問令牌到訪問咱們的信息
那到底整個過程的細節是怎樣的呢?我們開始分析請求響應包
這裏使用Fiddler抓包工具,去除了某些頭部,注意結合上面講的內容;爲了方便看報文,對其進行了換行處理;
重點關注:請求地址,響應狀態值,Location;請求和響應過程當中的參數下一小節分析
請求報文:直接請求到QQ服務器,知乎但願獲得的信息放到URL中。 GET請求中的關鍵參數有scope, state, redirect_uri, client_id, response_type
GET https://graph.qq.com/oauth2.0/authorize? scope=get_user_info%2Cget_info%2Cadd_t%2Cadd_pic_t%2Cget_other_info%2Cget_fanslist%2Cget_idollist%2Cadd_idol%2Cadd_share &state=8821ffbf09c3ff9c401fe404aa7fcaf7 &redirect_uri=https%3A%2F%2Fwww.zhihu.com%2Foauth%2Fcallback%2Fqqconn &response_type=code &client_id=100490701 HTTP/1.1 Host: graph.qq.com Referer: https://www.zhihu.com/
響應報文:響應302重定向到Location所在URL,也就是圖3的頁面,第二步的受權請求就是這裏的Location值,當點擊受權後表示用戶容許QQ將部分我的信息交給知乎,所以知乎將真正獲得這些權限。
HTTP/1.1 302 Moved Temporarily Location: https://graph.qq.com/oauth/show?which=Login &display=pc &scope=get_user_info%2Cget_info%2Cadd_t%2Cadd_pic_t%2Cget_other_info%2Cget_fanslist%2Cget_idollist%2Cadd_idol%2Cadd_share &state=8821ffbf09c3ff9c401fe404aa7fcaf7 &redirect_uri=https%3A%2F%2Fwww.zhihu.com%2Foauth%2Fcallback%2Fqqconn &response_type=code &client_id=100490701
受權請求
關鍵參數有scope, state, redirect_uri, client_id, response_type
請求報文
POST https://graph.qq.com/oauth2.0/authorize HTTP/1.1 Host: graph.qq.com Referer: https://graph.qq.com/oauth/show?which=Login &display=pc &scope=get_user_info%2Cget_info%2Cadd_t%2Cadd_pic_t%2Cget_other_info%2Cget_fanslist%2Cget_idollist%2Cadd_idol%2Cadd_share &state=8821ffbf09c3ff9c401fe404aa7fcaf7 &redirect_uri=https%3A%2F%2Fwww.zhihu.com%2Foauth%2Fcallback%2Fqqconn &response_type=code &client_id=100490701
受權響應
響應報文:重定向到Location上(redirect_url),也就是回到知乎,關鍵參數是code, state
HTTP/1.1 302 Moved Temporarily Location: https://www.zhihu.com/oauth/callback/qqconn? code=D38858BD4FE6058A48E461663ECB3CC3 &state=8821ffbf09c3ff9c401fe404aa7fcaf7
請求獲取token,最後訪問用戶的頭像,暱稱等信息
這一步對咱們是透明的,咱們看不到,其實就是簡單的調用API調用獲取,關鍵參數有grant_type, client_id, client_secret, code, redirect_uri
訪問令牌請求
下一小節有QQ API
受權服務器必須:
訪問令牌響應
響應:關鍵參數有access_token, refresh_token
若是訪問令牌請求是有效的且被受權,受權服務器頒發訪問令牌以及可選的刷新令牌。若是請求客戶端身份驗證失敗或無效,受權服務器返回錯誤響應。
QQ接入API
攻擊方式
假設 Alice 訪問 知乎網站(Client)請求 QQ 登陸受權(圖1), 知乎 請求 QQ(受權服務器) 受權以獲取 Alice 的信息,而後被重定向到 QQ服務器上(圖2),此時知乎綁定了當前是Alice用戶要進行QQ登陸受權(假設用cookie綁定,是能夠僞造的),接着 Alice 須要輸入用戶名和密碼認證第三方;
可是 Alice 不這樣作,沒有輸入用戶名和密碼,而是保存了這個 URL,而是讓 Bob 以某種方式去訪問這個URL,此時若是 Bob 用他的用戶名密碼登陸到QQ受權服務器認證,此時,QQ 用他的身份產生了一個 受權碼,重定向到知乎,此時至關於重複了一次請求到知乎,若是將cookie改成Alice本身的發回給知乎,那麼 Alice 在客戶端的帳號就被認證成功,而進行認證的身份倒是 Bob,可以獲取Bob的信息;
如何防止
客戶端應當基於當前須要認證的用戶以某種方式產生一個值,保證其惟一性,保存到服務端中,這個惟一值由客戶端發送給受權服務器,輸入用戶名密碼受權後,受權服務器將這個值原封不動的進行返回給客戶端,客戶端比較受權服務器返回的值和本身保存的值,若是和原來發送給受權服務器的不一致,就會拒絕,再也不獲取 access_token
如今好比 Alice 保存了這個 URL,讓 Bob 去登陸,此時客戶端會產生兩個state, 分別是stateA,stateB,知乎用 Alice 的身份stateA發送給QQ,而Bob登陸認證後,一樣是stateA被返回到 知乎,知乎比較Bob自己的stateB和返回的state是否相同,此時 知乎 比較將會失敗,拒絕下一步操做
state的惟一性防止了僞造攻擊
轉載請附上原地址:http://blog.bensonlin.me/blogs/oauth2