開放平臺鑑權以及OAuth2.0介紹
OAuth 2.0 協議
- OAuth是一個開發標準,允許使用者授權第三方網站或應用訪問他們儲存在另外的服務提供者上的資訊,而不需要將使用者名稱和密碼提供給第三方網站或分享他們資料的內容。
- OAuth 2.0不相容1.0。
協議的參與者
- RO (resource owner): 資源所有者,對資源具有授權能力的人。
- RS (resource server): 資源伺服器,它儲存資源,並處理對資源的訪問請求。
- Client: 第三方應用,它獲得RO的授權後便可以去訪問RO的資源。
- AS (authorization server): 授權伺服器,它認證RO的身份,為RO提供授權審批流程,並最終頒發授權令牌(Access Token)。
授權方式
在開放授權中,第三方應用(Client)可能是一個Web站點,也可能是在瀏覽器中執行的一段JavaScript程式碼,還可能是安裝在本地的一個應用程式。這些第三方應用都有各自的安全特性。對於Web站點來說,它與RO瀏覽器是分離的,它可以自己儲存協議中的敏感資料,這些金鑰可以不暴露給RO;對於JavaScript程式碼和本地安全的應用程式來說,它本來就執行在RO的瀏覽器中,RO是可以訪問到Client在協議中的敏感資料。
OAuth2.0為了支援這些不同型別的第三方應用,提出了下面四種授權型別:
- 授權碼 (Authorization Code Grant),適用於有server端的應用授權。
- 隱式授權 (Implicit Grant),適用於通過客戶端訪問的應用授權。
- 資源所有者密碼憑證許可 (Resource Owner Password Credentials Grant),OAuth簡化版,常用於移動應用認證,稱為xAuth。
- 受保護資源的客戶端授權 (Client Credentials Grant)。
流程 | Response Type(第一次請求) | Grant Type(第二次請求) | 可帶Refresh Token | 說明 |
---|---|---|---|---|
授權碼 | code | authorization_code | 是 | 常規流程 |
Implicit | token | - | 否 | 適用於純JS程式 |
使用者認證 | - | password | 是 | 客戶端高度可信,且授權碼流程不方便實施 |
客戶端 | - | client_credentials | 否 | 客戶端高度可信,擁有被操作資源(自用型),或操作非敏感資源 |
Authorization Code 授權
1. 授權場景
Authorization code 授權適用於PC,無線客戶端等需要和第三方server進行互動的應用場景。使用Authorization code授權,第三方能夠集中處理使用者的授權請求和授權結果,適用於有server端的應用。
2. 授權流程
Authorization code授權模式分為兩步,首先獲取authorization code,然後用code獲取acces token。
示意圖:
+----------+ | 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 +---------------+
3. 過程詳解
1、獲取Authorization Code
請求引數
- client_id 必須 分配給應用的appid
- redirect_uri 必須 授權回撥地址,必須和應用註冊的地址一致
- response_type 必須 授權型別,此值固定為“code”
- state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功授權後回撥時會原樣帶回。請務必嚴格按照流程檢查使用者與state引數狀態的繫結。
- scope 可選 授予許可權範圍
- 其他引數
如果使用者成功授權,則會跳轉到指定的回撥地址,並在redirect_uri地址後帶上Authorization Code和原始的state值
2、通過Authorization Code獲取Access Token
請求引數
- client_id 必須 分配給應用的appid
- grant_type 必須 授權型別,此值為:authorization_code
- client_secret 必須 分配給應用的secret
- state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功授權後回撥時會原樣帶回。請務必嚴格按照流程檢查使用者與state引數狀態的繫結。
- redirect_uri 必須 與上面一步中傳入的redirect_uri保持一致
- code 必須 上一步返回的Authorization Code值(必須設定此code的有效時間)
返回引數
- access_token 必須 授權令牌
- expires_in 必須 該access_token的有效期
- refresh_token 可選 在授權自動續期步驟中,獲取新的Access_Token時需要提供的引數
- 其他引數 可選
3、[可選] 許可權自動續期,獲取access_token
Access_token一般需要根據應用特性設定有效期,過期後需要使用者重新授權或採用自動續期的方式。
請求引數
- grant_type 必須 授權型別,在本步驟中,此值為“refresh_token”
- client_id 必須 分配給應用的appid
- refresh_token 必須 第二步返回的refresh_token
- client_secret 必須 分配給應用的secret
如果授權成功,則會返回和步驟二同樣的結果。
Implicit 授權
1. 授權場景
Implicit授權一般適用於沒有server端的客戶端應用,由客戶端發起授權請求,儲存和處理access_token,但有些應用(如web應用等)為了提高使用者體驗,簡化授權過程,也會常採用Implicit授權方式(注意,這種授權方式沒有返回refresh_token。)
2. 授權流程
示意圖:
+----------+ | 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) | | +---------+ +---------------+
互動圖:
3. 過程詳解
請求引數
- response_type 必須 授權型別,在本步驟中,此值為“token”
- client_id 必須 分配給應用的appid
- redirect_uri 必須 授權回撥地址,必須和應用註冊的地址一致
- scope 可選 授予許可權範圍
- state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功授權後回撥時會原樣帶回。請務必嚴格按照流程檢查使用者與state引數狀態的繫結。
- 其他引數 可選
如果成功授權,則會跳轉到redirect_uri指定的回撥地址,並帶上access_token、expires_in、state以及與應用相關的引數。注意,這種授權方式沒有返回refresh_token。
Resource Owner Password Credentials
該授權方式獲取access token一般只有一步,類似如下GET/POST請求:https://open.xxx.com/oauth2/access_token?client_id=xxxx&client_secret=xxxxx&grant_type=password&username=xxx&password=xxx
OAuth2.0新特性
- 伺服器角色區分:授權伺服器和資源伺服器
- 區別不同的使用者型別、授權場景和授權流程
- 將token分為頻繁傳輸使用但是有效時長較短的Access Token和用於更新Access Token的Refresh Token
- 定義多種token,降低資源請求的構造難度
- 授權過程不簽名,可根據需要採用HTTPS加密傳輸、驗證客戶端金鑰(通過簽名)、客戶端註冊時預先指定callback地址等手段。
- 明確引入客戶端註冊流程:確定Client Type、callback URL以及其它資訊
- 引入可選的state引數,幫助客戶端防範CSRF和管理狀態
- 引入scope引數,可以進行授權範圍控制
- token type等可被擴充套件: bearer(HTTPS), mac(HTTP+sign), etc.
淘寶的OAuth2.0安全控制
- 只支援HTTPS(bears),不支援簽名(簽名是走以前老的授權方式)
- 授權過程指定的callback URL必須與註冊的callback URL在同一個域名,或者為um:ietf:wg:oauth:2.0:oob(表示只顯示授權碼,不回撥callback URL)
- 介面分不同級別(R1, R2, W1, W2),同一Token對不同級別介面有不同的有效期
- 介面許可權劃分(item, promotion, user, etc.)
********轉載:https://www.cnblogs.com/duanxz/p/4369738.html協議設計中,為什麼要使用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的擴充套件授權型別解決方案,它在滿足相同安全性的條件下,使協議更簡潔,互動次數更少。
OAuth 2.0 協議
- OAuth是一個開發標準,允許使用者授權第三方網站或應用訪問他們儲存在另外的服務提供者上的資訊,而不需要將使用者名稱和密碼提供給第三方網站或分享他們資料的內容。
- OAuth 2.0不相容1.0。
協議的參與者
- RO (resource owner): 資源所有者,對資源具有授權能力的人。
- RS (resource server): 資源伺服器,它儲存資源,並處理對資源的訪問請求。
- Client: 第三方應用,它獲得RO的授權後便可以去訪問RO的資源。
- AS (authorization server): 授權伺服器,它認證RO的身份,為RO提供授權審批流程,並最終頒發授權令牌(Access Token)。
授權方式
在開放授權中,第三方應用(Client)可能是一個Web站點,也可能是在瀏覽器中執行的一段JavaScript程式碼,還可能是安裝在本地的一個應用程式。這些第三方應用都有各自的安全特性。對於Web站點來說,它與RO瀏覽器是分離的,它可以自己儲存協議中的敏感資料,這些金鑰可以不暴露給RO;對於JavaScript程式碼和本地安全的應用程式來說,它本來就執行在RO的瀏覽器中,RO是可以訪問到Client在協議中的敏感資料。
OAuth2.0為了支援這些不同型別的第三方應用,提出了下面四種授權型別:
- 授權碼 (Authorization Code Grant),適用於有server端的應用授權。
- 隱式授權 (Implicit Grant),適用於通過客戶端訪問的應用授權。
- 資源所有者密碼憑證許可 (Resource Owner Password Credentials Grant),OAuth簡化版,常用於移動應用認證,稱為xAuth。
- 受保護資源的客戶端授權 (Client Credentials Grant)。
流程 | Response Type(第一次請求) | Grant Type(第二次請求) | 可帶Refresh Token | 說明 |
---|---|---|---|---|
授權碼 | code | authorization_code | 是 | 常規流程 |
Implicit | token | - | 否 | 適用於純JS程式 |
使用者認證 | - | password | 是 | 客戶端高度可信,且授權碼流程不方便實施 |
客戶端 | - | client_credentials | 否 | 客戶端高度可信,擁有被操作資源(自用型),或操作非敏感資源 |
Authorization Code 授權
1. 授權場景
Authorization code 授權適用於PC,無線客戶端等需要和第三方server進行互動的應用場景。使用Authorization code授權,第三方能夠集中處理使用者的授權請求和授權結果,適用於有server端的應用。
2. 授權流程
Authorization code授權模式分為兩步,首先獲取authorization code,然後用code獲取acces token。
示意圖:
+----------+ | 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 +---------------+
3. 過程詳解
1、獲取Authorization Code
請求引數
- client_id 必須 分配給應用的appid
- redirect_uri 必須 授權回撥地址,必須和應用註冊的地址一致
- response_type 必須 授權型別,此值固定為“code”
- state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功授權後回撥時會原樣帶回。請務必嚴格按照流程檢查使用者與state引數狀態的繫結。
- scope 可選 授予許可權範圍
- 其他引數
如果使用者成功授權,則會跳轉到指定的回撥地址,並在redirect_uri地址後帶上Authorization Code和原始的state值
2、通過Authorization Code獲取Access Token
請求引數
- client_id 必須 分配給應用的appid
- grant_type 必須 授權型別,此值為:authorization_code
- client_secret 必須 分配給應用的secret
- state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功授權後回撥時會原樣帶回。請務必嚴格按照流程檢查使用者與state引數狀態的繫結。
- redirect_uri 必須 與上面一步中傳入的redirect_uri保持一致
- code 必須 上一步返回的Authorization Code值(必須設定此code的有效時間)
返回引數
- access_token 必須 授權令牌
- expires_in 必須 該access_token的有效期
- refresh_token 可選 在授權自動續期步驟中,獲取新的Access_Token時需要提供的引數
- 其他引數 可選
3、[可選] 許可權自動續期,獲取access_token
Access_token一般需要根據應用特性設定有效期,過期後需要使用者重新授權或採用自動續期的方式。
請求引數
- grant_type 必須 授權型別,在本步驟中,此值為“refresh_token”
- client_id 必須 分配給應用的appid
- refresh_token 必須 第二步返回的refresh_token
- client_secret 必須 分配給應用的secret
如果授權成功,則會返回和步驟二同樣的結果。
Implicit 授權
1. 授權場景
Implicit授權一般適用於沒有server端的客戶端應用,由客戶端發起授權請求,儲存和處理access_token,但有些應用(如web應用等)為了提高使用者體驗,簡化授權過程,也會常採用Implicit授權方式(注意,這種授權方式沒有返回refresh_token。)
2. 授權流程
示意圖:
+----------+ | 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) | | +---------+ +---------------+
互動圖:
3. 過程詳解
請求引數
- response_type 必須 授權型別,在本步驟中,此值為“token”
- client_id 必須 分配給應用的appid
- redirect_uri 必須 授權回撥地址,必須和應用註冊的地址一致
- scope 可選 授予許可權範圍
- state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功授權後回撥時會原樣帶回。請務必嚴格按照流程檢查使用者與state引數狀態的繫結。
- 其他引數 可選
如果成功授權,則會跳轉到redirect_uri指定的回撥地址,並帶上access_token、expires_in、state以及與應用相關的引數。注意,這種授權方式沒有返回refresh_token。
Resource Owner Password Credentials
該授權方式獲取access token一般只有一步,類似如下GET/POST請求:https://open.xxx.com/oauth2/access_token?client_id=xxxx&client_secret=xxxxx&grant_type=password&username=xxx&password=xxx
OAuth2.0新特性
- 伺服器角色區分:授權伺服器和資源伺服器
- 區別不同的使用者型別、授權場景和授權流程
- 將token分為頻繁傳輸使用但是有效時長較短的Access Token和用於更新Access Token的Refresh Token
- 定義多種token,降低資源請求的構造難度
- 授權過程不簽名,可根據需要採用HTTPS加密傳輸、驗證客戶端金鑰(通過簽名)、客戶端註冊時預先指定callback地址等手段。
- 明確引入客戶端註冊流程:確定Client Type、callback URL以及其它資訊
- 引入可選的state引數,幫助客戶端防範CSRF和管理狀態
- 引入scope引數,可以進行授權範圍控制
- token type等可被擴充套件: bearer(HTTPS), mac(HTTP+sign), etc.
淘寶的OAuth2.0安全控制
- 只支援HTTPS(bears),不支援簽名(簽名是走以前老的授權方式)
- 授權過程指定的callback URL必須與註冊的callback URL在同一個域名,或者為um:ietf:wg:oauth:2.0:oob(表示只顯示授權碼,不回撥callback URL)
- 介面分不同級別(R1, R2, W1, W2),同一Token對不同級別介面有不同的有效期
- 介面許可權劃分(item, promotion, user, etc.)
協議設計中,為什麼要使用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的擴充套件授權型別解決方案,它在滿足相同安全性的條件下,使協議更簡潔,互動次數更少。