從前端安全出發理解OAuth2.0

OAuth2.0是一套很是經典、流行的受權框架,可是咱們在學習和使用它的過程當中會以爲它的受權認證流程很是繁瑣,形成學習和使用OAuth2.0的時間成本很高。因此今天我將從前端安全的角度出發,使用一些針對受權流程的攻擊手段和策略經過攻防演練的方式向你展現OAuth2.0是如何經過複雜的受權流程與巧妙的設計來防護攻擊者的攻擊。javascript

簡要介紹OAuth 2.0

​ OAuth2.0是一套受權框架,它定義了 用戶 經過 受權服務器第三方應用 進行受權的過程。提供了讓用戶無需在第三方應用上輸入帳號密碼便可安全的對第三方應用進行受權的能力。OAuth2.0針對應用所處的運行環境制定了四種受權模式,今天咱們主要討論其中認證流程最完整、嚴密的受權碼模式。php

爲了方便和專一於咱們今天所討論的主題,因此我將OAuth2.0框架所定義的角色和流程縮減爲下圖的三個角色、四步流程。(須要格外關注的是除第一步用戶受權流程是 第三方應用的客戶端受權服務器 進行通訊,其餘流程均在 第三方應用的服務端受權服務器 間通訊完成)前端

攻擊策略一:中間人攻擊

​ 中間人攻擊的主要原理是攻擊者經過假裝將本身置於兩個端的通訊網絡中,造成一個「中轉站」,其主要攻擊方式是對通訊信息的竊取與篡改。而針對通常受權流程(如非OAuth2.0)的中間人攻擊,攻擊者每每經過劫持或僞造基站、網卡、wifi等通訊服務竊取客戶端與服務端中明文傳輸的令牌來獲取用戶所受權的信息與權利。java

經過簡單的介紹咱們能夠了解到如下幾個中間人攻擊的特徵:數據庫

  1. 攻擊者主要針對通信網絡且都是他可以滲透到的通訊網絡,且是明文傳輸的。
  2. 攻擊者要假裝本身。反過來講,不能讓被攻擊者警覺。

在瞭解了中間人攻擊的主要過程和特徵後,咱們就能夠對症下藥,看看OAuth2.0是如何防護住中間人攻擊的:瀏覽器

在整個OAuth2.0受權認證流程中,絕大部分的通訊發生在第三方應用的服務端與受權服務器之間這就能夠保證這部分通訊是不會被攻擊者竊取的,可是還有一部分通訊流程是可能被暴露在攻擊者眼前的,就如第三方應用的客戶端與服務端之間的通訊可能就被用戶手機自動鏈接上的免費wifi所監聽着。OAuth2.0對此的防護策略就是全部須要加密的、可靠的信息都由服務端之間的通訊進行交換好比令牌、密鑰和用戶信息等。而可能會遭受中間人攻擊的客戶端與服務端的通訊則默認其通訊信息已經被竊取或篡改,故而只讓它交換公開的、不可靠的信息,如公鑰和受權碼。固然針對中間人攻擊最有效的解決辦法仍是經過HTTPS協議將通訊信息加密,可是OAuth2.0的出現正是解決了針對HTTP協議安全受權的問題,因此不得不討論最壞的狀況。緩存

以上咱們已經充分利用中間人攻擊的第一個特徵進行防護,可是畢竟終歸有暴露在攻擊者眼前的通訊信息:受權碼。如何保證攻擊者不會拿到受權碼後進一步騙取受權服務器對其頒發令牌呢?這就要開始解釋爲何上文提到受權碼是不可靠的信息,首先介紹受權碼的兩個特色:安全

  1. 時效短,一般只有五分鐘有效期
  2. 只能使用一次

針對受權碼的兩個特色咱們想象一下這樣兩個攻擊場景,攻擊者由於是中間人因此一定比客戶端要提早拿到受權碼,若是攻擊者沒有使用該受權碼直接將其轉給了客戶端,客戶端使用後因爲受權碼只能使用一次的特色攻擊者必然沒法重複使用所以攻擊失敗。若是攻擊者率先使用了受權碼,而且將使用後的受權碼或僞造的受權碼傳遞給客戶端,那麼客戶端必然會受權失敗從而引發用戶的警覺。固然,光警覺不夠,畢竟攻擊者成功拿到了受權碼,那麼是什麼機制攔截住了攻擊者用受權碼換取令牌的動做呢?就是上文咱們提到的,也是咱們下文常常要提的密鑰(secret)。服務器

應用ID與應用密鑰

​ 在介紹接下來的攻擊策略前,我須要先簡單介紹下應用ID(client_id)和應用密鑰(client_secret)的來歷和用途。在OAuth2.0中規定第三方應用在接入受權服務前要先在受權服務方註冊應用,並提供應用受權回調頁(圖1中的第4步)等信息。註冊完成後受權服務方會給第三方應用兩個信息應用ID和應用密鑰,應用ID是識別應用的身份碼,可公開好比寫死在客戶端代碼中,應用密鑰是確認應用身份的信息,需保密只能在服務端中使用。用一句話歸納就是:應用ID告訴受權服務器「我」是誰,而應用密鑰則是讓受權服務器相信「我」是「我」。網絡

攻擊策略二:CSRF綁定劫持

​ 咱們知道CSRF的主要攻擊過程是構造惡意連接,誘騙用戶點擊。而在通常的受權過程當中攻擊者每每使用一種叫作綁定劫持的攻擊策略,將攻擊者的帳號與被攻擊者的帳號綁定在一塊兒。那麼如何理解綁定劫持呢?舉個例子,咱們玩遊戲一般最痛恨盜號狗,由於盜號者經過某些方法登陸上了咱們的遊戲帳號給咱們形成了損失。而綁定劫持則偏偏相反,綁定劫持指的是攻擊者誘騙被攻擊者登陸了攻擊者的帳號,好比被攻擊者的遊戲帳號被誘騙登陸並綁定了攻擊者的帳號,那麼攻擊者即可以瓜熟蒂落的登陸上被攻擊者的遊戲帳號了。

​ 在OAuth2.0受權流程中這樣的惡意連接極易構建:只須要攻擊者正常受權第三方應用,但將回調地址故意填錯或僞造,受權服務器就會帶着攻擊者的受權碼重定向到這個錯誤的地址,而這個受權碼天然也就不曾被使用過。此時攻擊者再將這個錯誤的地址改成正確的回調地址,並將這個連接發送給被攻擊者,誘騙其點擊。被攻擊者就天然而然的進行了受權碼換令牌,令牌換…的過程,這一套受權認證流程通過後就成功登陸上了被攻擊者的帳號落入了攻擊者的圈套。

​ OAuth2.0防護CSRF綁定劫持的方法很是巧妙。它經過設置一個字段state其值爲hash。在第三方應用獲取受權碼時將其傳遞給受權服務器,在受權服務器帶着受權碼重定向到第三方應用服務端時再將state原封不動傳回,第三方應用服務端會校驗先後兩次state是否相同。相同則證實受權者與登陸者是同一人,不相同則拒絕該登陸請求防止CSRF綁定劫持。值得思考的是state字段在OAuth2.0中是做爲一個選填字段使用的,我猜測可能這種登陸上攻擊者帳號的攻擊方式對被攻擊者的風險更小吧。

攻擊策略三:CSRF僞造重定向地址

​ 這也是一個基於CSRF的攻擊策略,只不過它針對的攻擊對象是相似OAuth2.0這種帶有重定向操做的受權認證流程。它的攻擊方式是經過構造虛假回調地址,利用受權服務對回調地址檢查不嚴的漏洞,將被攻擊者引入事先構造好的網頁,竊取其受權信息。

​ 值得注意的是,文中提到的「事先構造好的網頁」不單指攻擊者搭建的網站,也多是第三方應用中某些用戶能夠輸入內容的網頁,通過攻擊者構造後即可以竊取受權認證信息。舉個例子:假設第三方應用上有個網頁支持用戶評論、支持用戶插入連接圖片且沒有將用戶插入的連接地址洗成第三方應用的連接地址。那麼攻擊者即可以將我的服務器上的圖片資源連接地址上傳至該網頁評論處,而後構造受權連接並將回調地址填寫成該評論網頁,此時可能因爲該網頁與第三方應用的受權頁同屬於相同的一級域名就繞過了檢查。此時受權服務器帶着受權信息重定向到這個評論網頁,在查詢字符串中的全部受權信息便會都在referer字段中一併暴露給攻擊者。

這個問題其實不算嚴重,畢竟上文中間人攻擊那裏也說過了回調頁拿到的受權碼信息並不可靠,並且還有應用密鑰的存在,使得受權碼沒法正常換取令牌。可是畢竟是重定向到了攻擊者構造的頁面上,如果配合其餘的攻擊手段可能問題會很嚴重,因此根治CSRF僞造重定向地址的方法就是嚴格校驗回調地址。如下的幾個回調地址就是攻擊者構造的惡意地址的典型。

example.com/auth/callba…

example.com/redirect.ph…

​ 按照OAuth2.0最嚴格的回調地址校驗規則來講,應用在受權服務方註冊的時候就應該已經規定好了重定向地址的路由,且不可帶參數,要全等於。不過安全向來都是相對的,如果單純的內部系統使用的受權服務,經過一下代碼取到hostname後和註冊應用裏的hostname比較下是否全等於也就足夠了:

const { hostname } = new URL(redirectURI)
複製代碼

攻擊策略四:DNS污染

​ DNS污染的目的其實CSRF僞造重定向地址是相同的,都是想讓被攻擊者重定向到攻擊者構造到網頁,不一樣的是DNS污染成本更高,攻擊範圍更廣。咱們知道DNS是爲瀏覽器提供域名到IP地址映射信息服務的分佈式數據庫,當下遊DNS服務找不到某域名與IP地址的映射時會往上游進行請求查詢。找到映射後爲了下次查詢的快速相應,下游DNS服務會緩存以前查詢的結果,而DNS污染就是攻擊者經過某些手段改寫了DNS服務中的緩存。由此可想象的到,即使是受權服務器作足了回調地址的檢查工做也不免會讓第三方應用在查詢受污染的DNS服務後跳到攻擊者惡意構造的網站中。到了這一步也就只有上文提到的應用密鑰能夠保證攻擊者拿不到令牌和用戶信息。

總結

​ 以上展現的就是OAuth2.0防護常見的針對受權流程攻擊的設計實現。在OAuth2.0設計理念中我認爲最關鍵的核心就是 公開的信息短效且不信任、保密的信息只經過服務端傳遞和保存

​ 複雜邏輯 + 弱約束 = 容易滋生漏洞

​ 由於OAuth2.0流程很是複雜而且其標準對開發者的技術實現和細節約束很弱,因此在咱們開發者實現或接入OAtuh2.0 過程當中必定要明白OAuth2.0設計的原理,就好比當咱們明白了保密信息只能經過服務端傳遞和保存後就不會作出將令牌存放在Cookies這樣的操做。

​ 最後,OAuth2.0中還有不少細節咱們沒有去討論,好比token的生成須要回調地址的參與、做用域(scope)的安全做用。可是咱們要明白OAuth2.0對受權流程的設定絕非一個字段防護一種攻擊這麼簡單,而是經過多個字段、流程的配合編織成一張致密的網絡來完成防護功能。一樣的,攻擊者的攻擊手段也每每不是咱們演示的這麼簡單、單一,每每攻擊者會針對開發者功能實現上的漏洞打出一整套組合拳。因此對於咱們開發者來講明白核心原理才能在技術細節上少出紕漏畢竟永遠沒有最安全,只有更安全。

相關文章
相關標籤/搜索