理解 OAuth2.0

文章轉載於阮一峯老師的博客:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.htmlphp

參考文章:https://learnku.com/articles/20082html

 1、應用場景json

       爲了理解 OAuth 的適用場景,阮老師在這裏舉了一個例子說明,以下:api

       有一個 "雲沖印" 的網站,能夠將用戶存儲在 Google 的照片,沖印出來。這裏須要說明一下"雲沖印"相對於 Google 是一個第三方。瀏覽器

那麼若是要想讓"雲沖印"可以打印用戶存儲在 Google 上的照片,就必需要能讓"雲沖印"能讀取用戶存儲在 Google 上的照片。安全

       問題來了,Google 確定不會讓一個未經用戶受權的第三方去讀取用戶存儲在 Google 上的照片,那麼"雲沖印"怎麼獲取用戶的受權?服務器

       傳統的方法就是用戶將本身 Google 的賬號密碼告訴"雲沖印",後者就能夠拿着賬號密碼登陸 Google 去讀取用戶的照片了,可是這時cookie

你們確定會想到這很不安全,都有哪些風險呢?session

       1 若是"雲沖印"保存了用戶的賬號密碼,那這樣很不安全app

       2 "雲沖印"有了用戶的賬號密碼後,就擁有了和用戶同樣的權限能夠讀取用戶全部的資料,用戶沒辦法限制"雲沖印"得到受權的範圍和

有效期

       3 用戶只有修改密碼,才能收回"雲沖印"的權限,可是這樣作,會使得其餘全部得到用戶受權的第三方應用程序失效

       4 若是其中一個第三方應用程序被破解,那麼用戶的賬號密碼泄露

       OAuth 就是爲了解決上面的問題誕生的

2、名詞定義

       1 Third-party application:第三方應用程序,本文中又稱"客戶端(client)",即上面例子中的"雲沖印"

       2 HTTP service:HTTP 服務提供商,本文中簡稱"服務提供商",即上面例子中的"Google"

       3 Resource Owner:資源擁有者,本文中指的是"用戶"

       4 User Agent:用戶代理,本文中就是瀏覽器

       5 Authorization server: 認證服務器,服務提供商專門用來解決認證處理的服務器

       6 Resource server:資源服務器,服務提供商存放用戶所擁有資源的服務器,它與認證服務器能夠是一臺服務器也能夠不是一臺服務器

      瞭解了上面這些名詞,能夠知道,OAuth 其實就是"客戶端"安全可控的獲取"用戶受權",與"服務提供商"交互 

3、OAuth 的思路

       OAuth 在客戶端和服務提供商之間,設置了一個"受權層",客戶端不能直接登陸服務提供商,只能登陸受權層,以此將用戶和客戶端區分

開來,客戶端登陸受權層所用的令牌(token),與用戶的密碼不一樣。用戶在登陸的時候能夠指定受權層令牌的權限範圍和有效期

       客戶端登陸受權層以後,服務提供商根據令牌的權限範圍和有效期,向客戶端開放用戶存儲的資料

4、運行流程

       OAuth2.0 的運行流程以下圖:

    A: 用戶打開客戶端之後,客戶端須要用戶給與權限

    B:用戶贊成給與客戶端受權

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

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

    E:客戶端使用令牌,向資源服務器申請得到資源

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

    上面六步中,B 是關鍵的一步,用戶怎麼才能客戶端受權,客戶端被受權後訪問認證服務器申請令牌,而後憑藉有效的令牌訪問資源服務器,

下面看一下客戶端獲取受權的四種模式

5、客戶端的受權模式

      客戶端必須得到用戶受權以後,才能拿到令牌(access token),OAuth2.0 提供了四種受權方式,阮一峯老師的博客裏面詳解每一種,在這裏我

只介紹下經常使用的兩種模式

      受權碼模式(authorization code)

      簡化模式(implicit)

6、受權碼模式

      受權碼模式是目前功能最完善,流程最嚴密的受權模式,它的特色就是經過客戶端的後臺服務器和服務提供商的認證服務器進行互動,以下圖:

       A:用戶訪問客戶端,客戶端將用戶導向認證服務器

       B:此時會彈出相關頁面讓用戶選擇是否贊成受權給客戶端

       C:假設用戶贊成給與受權,認證服務器將用戶導向事先指定好的"重定向URI",同時附上一個受權碼(authorization code)

       D:客戶端收到受權碼以後,附上以前的重定向URI,向認證服務器申請令牌(access token),這一步是在客戶端的服務器上完成的

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

       下面是上面這些步驟所須要的參數

       A 步驟中,客戶端申請認證的URI:

       response_type:表示受權類型,必選項,此處爲固定值 "code"

       client_id:表示客戶端的ID,必選項

       redirect_uri:表示重定向 URI,可選項

       scope:表示申請的權限範圍,可選項

       state:表示客戶端當前狀態,能夠試任意值,認證服務器會原封不動的返回這個值

       以下示例:

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

  C 步驟中,認證服務器返回給客戶端的參數:

       code:受權碼,受權碼的有效期比較短,而且只能使用一次

       state:若是客戶端中的請求中包含這個參數,則認證服務器必須原封不動的迴應這樣一個參數

       以下示例:

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
          &state=xyz

  D 步驟中,客戶端向認證服務器申請令牌的HTTP請求的參數:

       grant_type:表示使用的受權模式,此處爲固定值:authorization code

       code:表示上一步獲取的受權碼,必填

       redirect_uri:表示重定向URI,若是受權請求中包含 redirect_uri 則返回時必填

       client_id:客戶端 ID

       以下示例:

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 步驟認證服務器向客戶端發送的請求回覆參數:

       access_token:表示令牌

       token_type:表示令牌類型,該值大小寫不敏感,必選項,能夠是bearer類型或mac類型

       expires_in:表示過時時間,單位爲秒

       refresh_token:表示更新令牌,用來獲取下一次令牌

       scope:表示權限範圍,若是與客戶端申請的範圍一致,能夠省略

       以下示例:

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"
     }

 

7、簡化模式

       簡化模式(簡化獲取受權碼流程)不經過第三方應用程序的服務器,直接在瀏覽器中向認證服務器申請令牌,跳過"受權碼"這個流程,

全部步驟都是在瀏覽器中完成的,以下圖所示:

      步驟以下:

      A:用戶訪問客戶端,客戶端將用戶導向認證服務器

      B:用戶決定是否給與客戶端受權

      C:假設用戶贊成受權,認證服務器將用戶導向客戶端指定的"重定向URI",並在 URI的 HASH 部分包含了訪問令牌

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

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

      F:瀏覽器執行上一步獲取得腳本,提取出令牌

      G:瀏覽器將令牌發給客戶端

      下面是上面步驟中所須要的參數:

      A 步驟客戶端發出的 HTTP 請求參數:

      response_type:表示受權類型,此處的值爲固定值"token"

      client_id:表示客戶端的 ID

      redirect_uri:表示重定向 URI

      scope:表示受權範圍

      state:表示客戶端狀態,能夠指定任意值,認證服務器會原封不動的返回這個值

      以下示例:

GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
    Host: server.example.com

  C步驟中,認證服務器迴應客戶端的URI:

       access_token:表示訪問令牌

       token_type:表示令牌類型

       expires_in:表示過時時間

       scope:表示權限範圍

       state:若是客戶端的請求中包含這個參數,則認證服務器的迴應中也須要包含一個如出一轍的參數

       以下示例:

 HTTP/1.1 302 Found
     Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
               &state=xyz&token_type=example&expires_in=3600

  在上面的例子中,認證服務器用 HTTP 頭信息的 Location 欄,指定瀏覽器重定向的網址,注意,這個網址的 HASH 部分包含了令牌,

根據上面的步驟,下一步瀏覽器會訪問Location指定的網址,可是 HASH 部分不會被髮送,而後資源服務器發送過來的代碼,會提取出HASH

中的令牌

 

-----------------------------------------2019/03/29----------------------------------------------

關於 OAuth2.0 中的 state 參數 

          在看完阮一峯老師的文章關於使用受權碼模式實現受權登陸後關於 state 這個參數就有一點疑問,其中阮一峯老師在文章中講到,若是客

戶端的傳遞參數中包含 state 這個參數,則服務端必需要原封不動傳遞回來,阮老師也沒有具體說到這個參數的真正做用,後來看了相關文章後,

這個參數能夠說是必傳的參數,若是少了這個參數可能會形成 CSRF 攻擊

           咱們經過一個常見場景說一下,參考文章:https://blog.csdn.net/gjb724332682/article/details/54428808

           1. 用戶 A 登陸一個第三方站點,如今用戶想要把這個第三方站點的賬號和本身的微博賬號進行綁定,此時用戶到了綁定頁面,可是尚未

綁定,在綁定頁面提功力一個綁定按鈕:"綁定微博" (地址a:http://aaa.com/index.php?m=user_3rd_bind_sina)

            2.用戶點擊綁定按鈕,第三方站點會將用戶導向微博的認證服務器(該過程用戶無感知),而後認證服務器會彈出一個頁面詢問用戶是否贊成

受權,用戶贊成受權以後認證服務器會將用戶導向第三方站點請求參數裏面的回跳地址,並返回受權碼

            該過程當中涉及到的一些請求參數,第三方站點將用戶導向認證服務器時的請求:https://api.weibo.com/oauth2/authorize?client_id=&redirect

_url=【http://aaa.com/index.php?m=user_3rd_bind_sina】&response_type=code

           認證服務器返回給第三方站點的地址:http://aaa.com/index.php?m=user_3rd_bind_sina&code=【受權碼】

           從上面認證服務返回給第三方站點的地址來看實際上是和當前登陸用戶一點關係都沒有,這個地址只能證實微博用戶信息,沒有一個標識能證實

第三方站點的用戶信息,這樣就出現了漏洞。

           假設如今有甲和乙兩個用戶同時發起綁定請求,都在認證服務器返回受權碼這一步停下,而後甲和乙互換地址,會出現什麼樣的結果?

           由於返回受權碼的地址沒有任何標識能有效證實第三方站點當前登陸用戶信息,因此會出現甲綁定乙的微博賬號,乙綁定甲的微博賬號,而攻擊

者的目標就是獲取本身帳號的地址,而後誘騙已登陸第三方站點的用戶點擊,從而改變綁定關係,將用戶的微博賬號綁定到攻擊者的賬號

           爲了應對這種狀況,OAuth2.0加入了 state 這個參數,不少第三方開放平臺都會有這個參數,好比新浪微博的(https://open.weibo.com/wiki/Oauth

2/authorize),咱們可使用這個參數去驗證請求的有效性,第三方向認證服務器發送請求時帶上這個參數,認證服務器在返回的時候也須要帶上這個參數,

每一個用戶的state參數都是惟一的,若是檢驗傳遞過去的和返回的不同則認爲是不合法的,這樣就能夠有效的避免CSRF(跨站請求僞造)攻擊

           關於如何生成state參數,不一樣的開發者有本身的實現方式,通常狀況下都是一個隨機字符串將其保存在cookie或session中,回調時檢查cookie或ses

sion中該參數的有效性便可

相關文章
相關標籤/搜索