在開放受權中,第三方應用(Client)多是一個Web站點,也多是在瀏覽器中運行的一段JavaScript代碼,還多是安裝在本地的一個應用程序。這些第三方應用都有各自的安全特性。對於Web站點來講,它與RO瀏覽器是分離的,它能夠本身保存協議中的敏感數據,這些密鑰能夠不暴露給RO;對於JavaScript代碼和本地安全的應用程序來講,它原本就運行在RO的瀏覽器中,RO是能夠訪問到Client在協議中的敏感數據。web
OAuth2.0爲了支持這些不一樣類型的第三方應用,提出了下面四種受權類型:瀏覽器
流程 | Response Type(第一次請求) | Grant Type(第二次請求) | 可帶Refresh Token | 說明 |
---|---|---|---|---|
受權碼 | code | authorization_code | 是 | 常規流程 |
Implicit | token | - | 否 | 適用於純JS程序 |
用戶認證 | - | password | 是 | 客戶端高度可信,且受權碼流程不方便實施 |
客戶端 | - | client_credentials | 否 | 客戶端高度可信,擁有被操做資源(自用型),或操做非敏感資源 |
Authorization code 受權適用於PC,無線客戶端等須要和第三方server進行交互的應用場景。使用Authorization code受權,第三方可以集中處理用戶的受權請求和受權結果,適用於有server端的應用。安全
Authorization code受權模式分爲兩步,首先獲取authorization code,而後用code獲取acces token。服務器
示意圖:app
+----------+ | 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)------- Authorization Grant --------->| | | | | | | |<-(B)----------- Access Token -------------| | | | & Refresh Token | | | | | | | | +----------+ | | | |--(C)---- Access Token ---->| | | | | | | | | | | |<-(D)- Protected Resource --| Resource | | Authorization | | Client | | Server | | Server | | |--(E)---- Access Token ---->| | | | | | | | | | | |<-(F)- Invalid Token Error -| | | | | | +----------+ | | | | | | | |--(G)----------- Refresh Token ----------->| | | | | | | |<-(H)----------- Access Token -------------| | +--------+ & Optional Refresh Token +---------------+
一、獲取Authorization Code網站
請求參數加密
若是用戶成功受權,則會跳轉到指定的回調地址,並在redirect_uri地址後帶上Authorization Code和原始的state值spa
二、經過Authorization Code獲取Access Token設計
請求參數
返回參數
三、[可選] 權限自動續期,獲取access_token
Access_token通常須要根據應用特性設定有效期,過時後須要用戶從新受權或採用自動續期的方式。
請求參數
若是受權成功,則會返回和步驟二一樣的結果。
Implicit受權通常適用於沒有server端的客戶端應用,由客戶端發起受權請求,保存和處理access_token,但有些應用(如web應用等)爲了提升用戶體驗,簡化受權過程,也會常採用Implicit受權方式(注意,這種受權方式沒有返回refresh_token。)
示意圖:
+----------+ | Resource | | Owner | | | +----------+ ^ | (B) +----|-----+ Client Identifier +---------------+ | -+----(A)-- & Redirection URI --->| | | User- | | Authorization | | Agent -|----(B)-- User authenticates -->| Server | | | | | | |<---(C)--- Redirection URI ----<| | | | with Access Token +---------------+ | | in Fragment | | +---------------+ | |----(D)--- Redirection URI ---->| Web-Hosted | | | without Fragment | Client | | | | Resource | | (F) |<---(E)------- Script ---------<| | | | +---------------+ +-|--------+ | | (A) (G) Access Token | | ^ v +---------+ | | | Client | | | +---------+ Note: The lines illustrating steps (A) and (B) are broken into two parts as they pass through the user-agent.
交互圖:
+----------+ | Resource | | Owner | | | +----------+ v | Resource Owner (A) Password Credentials | v +---------+ +---------------+ | |>--(B)---- Resource Owner ------->| | | | Password Credentials | Authorization | | Client | | Server | | |<--(C)---- Access Token ---------<| | | | (w/ Optional Refresh Token) | | +---------+ +---------------+
交互圖:
請求參數
若是成功受權,則會跳轉到redirect_uri指定的回調地址,並帶上access_token、expires_in、state以及與應用相關的參數。注意,這種受權方式沒有返回refresh_token。
該受權方式獲取access token通常只有一步,相似以下GET/POST請求:https://open.xxx.com/oauth2/access_token?client_id=xxxx&client_secret=xxxxx&grant_type=password&username=xxx&password=xxx
協議設計中,爲何要使用authorization_code來交換access_token?這是讀者容易想到的一個問題。也就是說,在協議的第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,協議將變得更加簡潔,並且少一次Client與AS之間的交互,性能也更優。那爲什麼不這麼設計呢?協議文檔[1]中並無給出這樣設計的理由,但也不難分析:(1) 瀏覽器的redirect_uri是一個不安全信道,此方式不適合於傳遞敏感數據(如access_token)。由於uri可能經過HTTP referrer被傳遞給其它惡意站點,也可能存在於瀏覽器cacher或log文件中,這就給攻擊者盜取access_token帶來了不少機會。另外,此協議也不該該假設RO用戶代理的行爲是可信賴的,由於RO的瀏覽器可能早已被攻擊者植入了跨站腳本用來監聽access_token。所以,access_token經過RO的用戶代理傳遞給Client,會顯著擴大access_token被泄露的風險。 但authorization_code能夠經過redirect_uri方式來傳遞,是由於authorization_code並不像access_token同樣敏感。即便authorization_code被泄露,攻擊者也沒法直接拿到access_token,由於拿authorization_code去交換access_token是須要驗證Client的真實身份。也就是說,除了Client以外,其餘人拿authorization_code是沒有用的。 此外,access_token應該只頒發給Client使用,其餘任何主體(包括RO)都不該該獲取access_token。協議的設計應能保證Client是惟一有能力獲取access_token的主體。引入authorization_code以後,即可以保證Client是access_token的惟一持有人。固然,Client也是惟一的有義務須要保護access_token不被泄露。 (2) 引入authorization_code還會帶來以下的好處。因爲協議須要驗證Client的身份,若是不引入authorization_code,這個Client的身份認證只能經過第1步的redirect_uri來傳遞。一樣因爲redirect_uri是一個不安全信道,這就額外要求Client必須使用數字簽名技術來進行身份認證,而不能用簡單的密碼或口令認證方式。引入authorization_code以後,AS能夠直接對Client進行身份認證(見步驟4和5),並且能夠支持任意的Client認證方式(好比,簡單地直接將Client端密鑰發送給AS)。 在咱們理解了上述安全性考慮以後,讀者也許會有豁然開朗的感受,懂得了引入authorization_code的妙處。那麼,是否是必定要引入authorization_code才能解決這些安全問題呢?固然不是。筆者將會在另外一篇博文給出一個直接返回access_token的擴展受權類型解決方案,它在知足相同安全性的條件下,使協議更簡潔,交互次數更少。