OAuth2

爲何須要oAuth2?

假設有一個「雲筆記」產品,並提供了「雲筆記服務」和「雲相冊服務」,此時用戶須要在不一樣的設備(PC、Android、iPhone、TV、Watch)上去訪問這些「資源」(筆記,圖片)html

那麼用戶如何才能訪問屬於本身的那部分資源呢?此時傳統的作法就是提供本身的帳號和密碼給咱們的「雲筆記」,登陸成功後就能夠獲取資源了。但這樣的作法會有如下幾個問題:git

  • 「雲筆記服務」和「雲相冊服務」會分別部署,難道咱們要分別登陸嗎?
  • 若是有第三方應用程序想要接入咱們的「雲筆記」,難道須要用戶提供帳號和密碼給第三方應用程序,讓他記錄後再訪問咱們的資源嗎?
  • 用戶如何限制第三方應用程序在咱們「雲筆記」的受權範圍和使用期限?難道把全部資料都永久暴露給它嗎?
  • 若是用戶修改了密碼收回了權限,那麼全部第三方應用程序會所有失效.
  • 只要有一個接入的第三方應用程序遭到破解,那麼用戶的密碼就會泄露,後果不堪設想。

爲了解決相似以上問題oAuth2應用而生github

oAuth2是什麼?

OAuth(開放受權)是一個開放標準,容許用戶受權第三方移動應用訪問他們存儲在另外的服務提供者上的信息,而不須要將用戶名和密碼提供給第三方移動應用或分享他們數據的全部內容,OAuth2.0是OAuth協議的延續版本,但不向後兼容OAuth 1.0即徹底廢止了OAuth1.0。json

OAuth 2.0 的標準是 RFC 6749 文件。該文件先解釋了 OAuth是引入了一個受權層,用來分離兩種不一樣的角色:客戶端和資源全部者。......資源全部者贊成之後,資源服務器能夠向客戶端頒發令牌。客戶端經過令牌,去請求數據。OAuth 的核心就是向第三方應用頒發令牌。後端

oAuth的2規則中的名詞解釋

  • 第三方應用程序(Third-party application): 又稱之爲客戶端(client),好比上節中提到的設備(PC、Android、iPhone、TV、Watch),咱們會在這些設備中安裝咱們本身研發的 APP。又好比咱們的產品想要使用 QQ、微信等第三方登陸。對咱們的產品來講,QQ、微信登陸是第三方登陸系統。咱們又須要第三方登陸系統的資源(頭像、暱稱等)。對於 QQ、微信等系統咱們又是第三方應用程序。
  • HTTP 服務提供商(HTTP service): 咱們的雲筆記產品以及 QQ、微信等均可以稱之爲「服務提供商」。
  • 資源全部者(Resource Owner): 又稱之爲用戶(user)。
  • 用戶代理(User Agent): 好比瀏覽器,代替用戶去訪問這些資源。
  • 認證服務器(Authorization server): 即服務提供商專門用來處理認證的服務器,簡單點說就是登陸功能(驗證用戶的帳號密碼是否正確以及分配相應的權限)
  • 資源服務器(Resource server): 即服務提供商存放用戶生成的資源的服務器。它與認證服務器,能夠是同一臺服務器,也能夠是不一樣的服務器。簡單點說就是資源的訪問入口,好比上節中提到的「雲筆記服務」和「雲相冊服務」均可以稱之爲資源服務器。

oAuth2規則的運行

圖片描述

(A)用戶打開客戶端之後,客戶端要求用戶給予受權。api

(B)用戶贊成給予客戶端受權。瀏覽器

(C)客戶端使用上一步得到的受權,向認證服務器申請令牌。安全

(D)認證服務器對客戶端進行認證之後,確認無誤,贊成發放令牌。服務器

(E)客戶端使用令牌,向資源服務器申請獲取資源。微信

(F)資源服務器確認令牌無誤,贊成向客戶端開放資源。

oAuth2規則的客戶端受權方式

  • 受權碼模式(authorization code)

    (A)用戶訪問客戶端,後者將前者導向認證服務器。

    (B)用戶選擇是否給予客戶端受權。

    (C)假設用戶給予受權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個受權碼。

    (D)客戶端收到受權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見。

    (E)認證服務器覈對了受權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)。

  • 簡化模式(implicit)

    (A)客戶端將用戶導向認證服務器。

    (B)用戶決定是否給於客戶端受權。

    (C)假設用戶給予受權,認證服務器將用戶導向客戶端指定的"重定向URI",並在URI的Hash部分包含了訪問令牌。

    (D)瀏覽器向資源服務器發出請求,其中不包括上一步收到的Hash值。

    (E)資源服務器返回一個網頁,其中包含的代碼能夠獲取Hash值中的令牌。

    (F)瀏覽器執行上一步得到的腳本,提取出令牌。

    (G)瀏覽器將令牌發給客戶端。

  • 密碼模式(resource owner password credentials)

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

    (B)客戶端將用戶名和密碼發給認證服務器,向後者請求令牌。

    (C)認證服務器確認無誤後,向客戶端提供訪問令牌。

  • 客戶端模式(client credentials)

    (A)客戶端向認證服務器進行身份認證,並要求一個訪問令牌。

    (B)認證服務器確認無誤後,向客戶端提供訪問令牌。

oAuth2客戶端的受權碼模式詳細步驟

受權碼模式(authorization code)是功能最完整、流程最嚴密的受權模式。它的特色就是經過客戶端的後臺服務器,與"服務提供商"的認證服務器進行互動。

(A) 用戶訪問客戶端,後者將前者導向認證服務器;客戶端申請認證的URI,包含如下參數:

response_type:表示受權類型,必選項,此處的值固定爲"code"
client_id:表示客戶端的ID,必選項
redirect_uri:表示重定向URI,可選項
scope:表示申請的權限範圍,可選項
state:表示客戶端的當前狀態,任意字符串,認證服務器會原封不動地返回這個值,也是用來防止跨站點請求僞造攻擊,必選項

eg:
    GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
    &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1

(B) 用戶選擇是否給予客戶端受權。

(C) 假設用戶給予受權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個受權碼;
服務器迴應客戶端的URI,包含如下參數:

code:表示受權碼,必選項。該碼的有效期應該很短,一般設爲10分鐘,客戶端只能使用該碼一次,不然會被受權服務器拒絕。該碼與客戶端ID和重定向URI,是一一對應關係。
state:若是客戶端的請求中包含這個參數,認證服務器的迴應也必須如出一轍包含這個參數

eg:
    Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

(D) 客戶端收到受權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見;客戶端向認證服務器申請令牌的HTTP請求,包含如下參數:

grant_type:表示使用的受權模式,必選項,此處的值固定爲"authorization_code"。
code:表示上一步得到的受權碼,必選項。
redirect_uri:表示重定向URI 應用程序中的URL,用於在受權後發送用戶,必選項,且必須與A步驟中的該參數值保持一致。
client_id:表示應用程序的客戶端ID,必選項
client_secrect:表示應用程序的客戶機密也便是訪問的資源權限,必選項

eg:
    POST /token HTTP/1.1
    Host: server.example.com
    Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
    Content-Type: application/x-www-form-urlencoded
    grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
    &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

(E) 認證服務器覈對了受權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)和更新令牌(refresh token);認證服務器發送的HTTP回覆,包含如下參數:

access_token:表示訪問令牌,必選項。
token_type:表示令牌類型,該值大小寫不敏感,必選項,能夠是bearer類型或mac類型。
expires_in:表示過時時間,單位爲秒。若是省略該參數,必須其餘方式設置過時時間。
refresh_token:表示更新令牌,用來獲取下一次的訪問令牌,可選項。
scope:表示權限範圍,若是與客戶端申請的範圍一致,此項可省略。

eg:
    HTTP/1.1 200 OK
    Content-Type: application/json;charset=UTF-8
    Cache-Control: no-store
    Pragma: no-cache
    {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
    }

流程圖以下

圖片描述

更新令牌

令牌的有效期到了,若是讓用戶從新走一遍上面的流程,再申請一個新的令牌,極可能體驗很差,並且也沒有必要。OAuth 2.0 容許用戶自動更新令牌。

具體方法是,資源服務器頒發令牌的時候,一次性頒發兩個令牌,一個用於獲取數據,另外一個用於獲取新的令牌(refresh token 字段)。令牌到期前,用戶使用 refresh token 發一個請求,去更新令牌。

https://b.com/oauth/token?
        grant_type=refresh_token&
        client_id=CLIENT_ID&
        client_secret=CLIENT_SECRET&
        refresh_token=REFRESH_TOKEN

URL中,grant_type參數爲refresh_token表示要求更新令牌,client_id參數和client_secret參數用於確認身份,refresh_token參數就是用於更新令牌的令牌。資源服務器驗證經過之後,就會頒發新的令牌。

oAuth2 四種方式比較

密碼模式(resource owner password credentials)

  • 這種模式是最不推薦的,由於client可能存了用戶密碼
  • 這種模式主要用來作遺留項目升級爲oauth2的適配方案
  • 固然若是client是自家的應用,也是能夠
  • 支持refresh token

受權碼模式(authorization code)

  • 這種模式算是正宗的oauth2的受權模式
  • 設計了auth code,經過這個code再獲取token
  • 支持refresh token

簡化模式(implicit)

  • 這種模式比受權碼模式少了code環節,回調url直接攜帶token
  • 這種模式的使用場景是基於瀏覽器的應用
  • 這種模式基於安全性考慮,建議把token時效設置短一些
  • 不支持refresh token

客戶端模式(client credentials)

  • 這種模式直接根據client的id和密鑰便可獲取token,無需用戶參與
  • 這種模式比較合適消費api的後端服務,好比拉取一組用戶信息等
  • 不支持refresh token,主要是沒有必要

    refresh token的初衷主要是爲了用戶體驗不想用戶重複輸入帳號密碼來換取新token,於是設計了refresh token用於換取新token

    這種模式因爲沒有用戶參與,並且也不須要用戶帳號密碼,僅僅根據本身的id和密鑰就能夠換取新token,於是不必refresh token

安全問題

  1. redirect_uri

    問:爲何 OAuth 2.0 要求申請 client_id 的時候必須輸入一個域名,而且要求 redirect_uri 必須是此域名下的地址?

    答:若是別人知道了咱們的 client_id,而後在第二部生成受權鏈接的時候,把 redirect_uri 替換成本身與域名下的,就會能獲取 code 並存放在本身服務器上

  2. code

    若是 第三反方服務 不支持https,就會有被劫持的風險。若是沒有 code,而是直接返回 access_tokenredirect_uri 中,中間人就能夠直接使用 access_token

  3. app_secret

    若是 code 被中間人獲取,在沒有 app_secret 的狀況下,就能夠直接用 code 換取 access_token。由於在整個獲取 code 的過程當中都是暴露在外的

  4. state

    state 參數若是利用起來,看成 CSRF Token,就能避免此事的發生:

    1. 攻擊者依舊獲取 code 並打算騙受害者點擊
    2. 受害者點擊連接,但因服務器(好比 chrisyue.com)分配給受害者的設備的 state 值和連接裏面的 state 值不同,服務器(chrisyue.com)直接返回驗證 state 失敗
`state` 或者說 `CSRF Token` 這種跟設備綁定的隨機字符串,只要稍微複雜一點,攻擊者根本就不可能猜得出來,而設置一個讓攻擊者猜不到的,跟設備或者說瀏覽器綁定的 state (CSRF token) 值,就是解決 CSRF 攻擊的關鍵。

oAuth2實現過程小結

關於Auth2的的實現機制,就是不一樣的客戶端須要向資源服務器經過請求令牌(access_token)來獲取不一樣的資源,服務器須要去驗證訪問的客戶端是不是在該資源服務器註冊過的,以及該客戶端被分配到的資源服務器的可訪問的權限是什麼,因此須要用戶首先被客戶端重定向到認證服務器來驗證它的身份,驗證經過,返回一個用來獲取token的只能使用一次的一個code碼做爲請求token的參數,客戶端請求token的時候還必須傳遞一個須要獲取資源權限的必選參數client_secrect,以及參數client_id(客戶端的身份),驗證經過,則客戶端獲取到資源並展現給用戶。

參考資料:
https://www.jianshu.com/p/a7d...
http://www.ruanyifeng.com/blo...
http://www.ruanyifeng.com/blo...
http://www.ruanyifeng.com/blo...
https://developer.github.com/...
https://www.jianshu.com/p/7b1...
相關文章
相關標籤/搜索