安全系列之二:OAuth2.0 開放受權協議

本文提取出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

下面是正文 工具

 

什麼是 OAuth

Open Authorization的縮寫,即開放受權協議

OAuth 的受權使應用無需涉及另外一方應用的賬號信息(如用戶名與密碼),只須要經過受權就能夠另外一方應用的信息,保證了安全性,不會泄露用戶名密碼。

而整個流程要怎麼作才能保證安全呢,該協議定義了規則。

更多的定義能夠本身查看OAuth的維基百科

舉個栗子

第一步:固然是上知乎官網登陸,點擊QQ頭像做爲QQ登陸

 圖1

第二步:登陸QQ並受權,能夠看到右邊是QQ受權給知乎的內容,獲取咱們的暱稱,頭像和性別等信息。輸入用戶名密碼登陸,能夠看到按鈕顯示的是登陸並受權,也就是是點擊後就已經說明咱們贊成讓知乎獲取咱們的這些我的信息。

 圖2

由於我已經登陸了,因此直接點上面的QQ頭像(頭像就是多啦A夢)直接受權。

 圖3

第三步:登陸受權成功,能夠在知乎的首頁看到你的信息(還須要補充知乎的我的信息做爲新用戶註冊)

 圖4

注意:有的網站受權,是先登陸後,進入另外一個頁面而後再點擊受權的。

PS:記住圖的編號,後面分析用到

下面將進入正題,首先是上面涉及的幾個角色,而後是協議流程等

幾個角色

前提:知乎要用QQ登陸,使用QQ的頭像和暱稱:

  • 資源全部者(Resource Owner):可以許可受保護資源訪問權限的實體。也就是擁有QQ資源(頭像/暱稱)的,也就是咱們。
  • 資源服務器(Resource Server):託管受保護資源的服務器,可以接收和響應使用訪問令牌對受保護資源的請求。也就是某個放置頭像信息的QQ服務器
  • 客戶端(Client):使用資源全部者的受權表明資源全部者發起對受保護資源的請求的應用程序。也就是正在使用的知乎
  • 受權服務器(Authorization Server):在成功驗證資源全部者且得到受權後頒發訪問令牌給客戶端的服務器。能夠和資源服務器是同一臺服務器,也能夠是分離的個體。這裏假設也是QQ服務器自己。

還有一個角色是資源全部者的用戶代理(User Agent),通常就是咱們的Web瀏覽器,咱們須要瀏覽器做爲代理纔可以進行操做

四種受權方式

本規範定義了四種許可類型——受權碼、隱式許可、資源全部者密碼憑據和客戶端憑據——以及用於定義其餘類型的可擴展性機制。其中受權碼是咱們最經常使用的,所以單獨講受權碼方式,其它類型詳情能夠自行下載RFC6749文檔查看,下載地址在這裏,搜索本身想要的文檔,而後右鍵另存爲下載便可

  • 受權碼:受權碼經過使用受權服務器做爲客戶端與資源全部者的中介而得到。客戶端不是直接從資源全部者請求受權,而是引導資源全部者至受權服務器受權服務器以後引導資源全部者帶着受權碼回到客戶端。在引導資源全部者攜帶受權碼返回客戶端前,受權服務器會鑑定資源全部者身份並得到其受權。因爲資源全部者只與受權服務器進行身份驗證,因此資源全部者的憑據不須要與客戶端分享。受權碼提供了一些重要的安全益處,例如驗證客戶端身份的能力,以及向客戶端直接的訪問令牌的傳輸而非經過資源全部者的用戶代理來傳送它而潛在暴露給他人(包括資源全部者)。
  • 隱式許可:在隱式許可流程中,再也不給客戶端頒發受權碼,取而代之的是客戶端直接被頒發一個訪問令牌(做爲資源所 有者的受權),受權服務器不對客戶端進行身份驗證。這種許可類型是隱式的,由於沒有中間憑據(如受權碼)被頒發(以後用於獲取訪問令牌)。
  • 資源全部者密碼憑據:資源全部者密碼憑據(即用戶名和密碼),能夠直接做爲獲取訪問令牌的受權許可。這種憑據只能應該 當資源全部者和客戶端之間具備高度信任時(例如,客戶端是設備的操做系統的一部分,或者是一個高度特權應用程序),以及當其餘受權許可類型(例如受權碼)不可用時被使用。
  • 客戶端憑據:當受權範圍限於客戶端控制下的受保護資源或事先與受權服務器商定的受保護資源時客戶端憑據能夠被 用做爲一種受權許可。典型的當客戶端表明本身(客戶端也是資源全部者)或者基於與受權服務器事先商定的受權請求對受保護資源的訪問權限時,客戶端憑據被用做爲受權許可。

能夠看到,受權碼模式(authorization code)是功能最完整、流程最嚴密的受權模式。

兩個令牌

  • 訪問令牌(access token):訪問令牌是用於訪問受保護資源的憑據(如知乎拿訪問令牌訪問受保護的咱們的暱稱和頭像等)。訪問令牌是一個表明受權服務器向客戶端頒發的受權的字符串。該字符串一般對於客戶端是不透明的。令牌表明了訪問權限的由資源全部者許可並由資源服務器和受權服務器實施的具體範圍和期限。(不透明的意思都知道吧,就是客戶端(知乎服務器)可以獲得訪問令牌,由於它要根據這個令牌去獲取QQ的我的信息。)
  • 刷新令牌由受權服務器頒發給客戶端,用於在當前訪問令牌失效或過時時,獲取一個新的訪問令牌,或者得到相等或更窄範圍的額外的訪問令牌(訪問令牌可能具備比資源全部者所受權的更短的生命週期和更少的權限)。頒發刷新令牌是可選的,由受權服務器決定。對客戶端也是不透明的

(受權碼許可)協議流程

+----------+ | 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文檔

解釋知乎的QQ受權

注意結合上面的協議流程看分析:

  1. 首先,用戶點擊QQ登陸時,知乎服務器會幫咱們重定向到QQ的第三方受權服務器上頁面上(圖3)請求受權(能夠看到,瀏覽器的地址是qq的地址,也就是說不會泄露QQ的密碼給知乎,須要注意的是,這個連接須要使用https協議,由於涉及用戶登陸的密碼),同時,跟隨一個重定向URL指向知乎服務器的某個地址,咱們點擊受權後(圖3),受權成功,重定向到知乎指定的URL並返回受權碼(能夠在URL看到)
  2. 接着知乎服務器發送同一個重定向URL和受權碼請求受權服務器的訪問令牌,最後若是QQ服務器校驗沒有問題,返回訪問令牌,最後知乎服務器調用QQ提供的API,附帶訪問令牌獲取用戶的信息

爲何要分紅兩點呢?由於第一點咱們能夠容易的抓取請求響應報文獲得,而獲取訪問令牌的過程對資源全部者(咱們用戶)是透明的,也就是說咱們不會看到訪問令牌,只有知乎服務器獲得了訪問令牌;其實看不到也不該該讓資源全部者看到,不然就不安全了,由於誰均可以用訪問令牌到訪問咱們的信息

那到底整個過程的細節是怎樣的呢?我們開始分析請求響應包

請求響應包和參數分析

這裏使用Fiddler抓包工具,去除了某些頭部,注意結合上面講的內容;爲了方便看報文,對其進行了換行處理;

重點關注:請求地址,響應狀態值,Location;請求和響應過程當中的參數下一小節分析

第一步:(知乎主頁點擊QQ登陸)

請求報文:直接請求到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
  • response_type:必選,固定是」code」
  • client_id:必選,是受權服務器頒發給已註冊客戶端客戶端標識,也就是說知乎開發人員到QQ處申請表示但願經過QQ受權接入,QQ贊成後會給知乎(client)一個惟一的標識,這樣之後受權登陸時,QQ方(受權服務器)就知道哪一個應用正在請求接入
  • scope:可選,表示知乎但願從QQ上獲得用戶的什麼權限。爲何第一步重定向要附帶scope,由於爲了防止咱們點擊受權時,有人惡意修改了URL,致使受權的內容變化了,有了第一步,QQ服務器能先知道須要什麼權限(參數內容是get_user_info之類的內容,能夠看到圖2中打鉤的選項其實就是根據scope獲得的),保存在QQ服務器中,而若是點擊受權後,傳到服務器的scope內容變了,那麼確定是有人修改了scope,受權將失敗,保證了安全性。
  • redirect_uri:可選,知乎但願跳轉的URL,指向本身網站的位置,一樣的,須要和第一步中的redirct_url相同,理由與scope相同
  • state:推薦的(應認爲是必需的),客戶端用於維護請求和回調之間的狀態的不透明的值。當重定向用戶代理回到客戶端時,受權服務器包含此值。該參數應該用於防止如跨站點請求僞造CSRF

受權響應

響應報文:重定向到Location上(redirect_url),也就是回到知乎,關鍵參數是code, state

HTTP/1.1 302 Moved Temporarily
Location: https://www.zhihu.com/oauth/callback/qqconn?
    code=D38858BD4FE6058A48E461663ECB3CC3
    &state=8821ffbf09c3ff9c401fe404aa7fcaf7
  • code:必需的。受權服務器生成的受權碼。受權碼必須在頒發後很快過時以減少泄露風險。推薦的最長的受權碼生命週期是 10 分鐘。客戶端不能使用受權碼超過一次。若是一個受權碼被使用一次以上,受權服務器必須拒絕該請求並應該撤銷(如可能)先前發出的基於該受權碼的全部令牌。受權碼與客戶端標識和重定向 URI 綁定。
  • state:必需的,若「state」參數在客戶端受權請求中提交。則返回同一個值。

第三步:訪問令牌請求和響應(知乎程序內部請求獲取令牌)

請求獲取token,最後訪問用戶的頭像,暱稱等信息

這一步對咱們是透明的,咱們看不到,其實就是簡單的調用API調用獲取,關鍵參數有grant_type, client_id, client_secret, code, redirect_uri

訪問令牌請求

下一小節有QQ API

  • grant_type:必需的。值必須被設置爲「authorization_code」。
  • code:從受權服務器收到的受權碼。
  • redirect_uri:必需的,必須和第一步請求時的redirect_uri相同。
  • client_id:必需的

受權服務器必須:

  • 要求機密客戶端或任何被頒發了客戶端憑據(或有其餘身份驗證要求)的客戶端進行客戶端身份驗證,
  • 若包括了客戶端身份驗證,驗證客戶端身份,
  • 確保受權碼頒發給了經過身份驗證的機密客戶端,或者若是客戶端是公開的,確保代碼頒發給了請求 中的「client_id」,
  • 驗證受權碼是有效的,並
  • 確保給出了「redirect_uri」參數,若「redirect_uri」參數如 4.1.1 所述包含在初始受權請求中,且若包含,確保它們的值是相同的。

訪問令牌響應

響應:關鍵參數有access_token, refresh_token

若是訪問令牌請求是有效的且被受權,受權服務器頒發訪問令牌以及可選的刷新令牌。若是請求客戶端身份驗證失敗或無效,受權服務器返回錯誤響應。

QQ API加深理解

QQ接入API

state 的理解

攻擊方式

假設 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

相關文章
相關標籤/搜索