OAuth 安全回顧簡要
你對 OAuth 採用的保護措施有多熟悉?你的系統是否遵循 OAuth 的開放標準?在實現用戶身份驗證流程時,你是否注意到了可能出現的風險?讓我們簡要回顧一下我們對 OAuth 的學習。
介紹
前幾天,一篇有趣的 OAuth 漏洞文章剛剛出爐。由 SALT 實驗室發表的 可能影響數百個在線服務的新 OAuth 漏洞 主題的文章。這篇特定的文章指出了一個在 Expo 中發現的漏洞,這是一個廣泛使用的實現 OAuth 和其他功能的框架。文章特別討論了 expo-auth-session 庫中的一個漏洞,該漏洞已被指定並妥善解決。
如果你對 OAuth 感興趣或正在開發像我們這樣的 CIAM 相關產品,我們強烈建議閱讀這篇文章。它非常具有啟發性,並提供了有用的見解。這些白帽報告提醒我們,即使是最簡單的功能也可能帶來漏洞。在網絡安全和授權問題上,我們必須小心謹慎,確保用戶信息的安全和隱私。如果這篇文章引起了你的注意,我相信你會非常同意我們的觀點。
這讓我想起了我們剛開始的時候。我們花了很多時間學習和研究 OAuth 和 OIDC 協議的細節。雖然這很痛苦和繁瑣,但收穫巨大。雖然我們團隊中的每個人並不都是 OAuth 專家,但每個人都致力於安全性和細緻努力。正是憑藉這些奉獻的努力,Logto 產品發展成為今天的樣子。
藉這個很好的機會,我們希望在這裡回顧一下 OAuth 的一些安全細節。
探索 OAuth 授權碼流程
OAuth 2.0 提供了各種授權流程,滿足不同客戶端類型和需求。這些流程包括 隱式流程、客戶端憑證流程、資源所有者密碼憑證流程,以及 設備授權流程。然而,授權碼流程被視為最安全且最廣泛使用的。與其他流程不同,授權碼流程將用戶身份驗證與客戶端應用分開,並涉及用授權碼交換令牌。這種方法提供了額外的安全層,因為敏感令牌從不暴露給客戶端。此外,授權碼流程支持服務器端令牌管理,適合需要強大安全性和增強用戶訪問控制的 Web 應用。
以下是一個最簡單的 授權碼流程 圖表:
讓我們看看授權碼授權流程中最關鍵的兩個請求,以及其中看似微不足道但卻在防欺詐中發揮關鍵作用的片段。
授權端點:
令牌交換端點:
客戶端憑證
在 OAuth 中,客戶端憑證 是用於認證和識別客戶端應用到授權服務器的憑證。這些憑證在客戶端註冊過程中獲得,並用於在客戶端向授權服務器發出請求時驗證客戶端的身份。(當你第一次註冊應用程序時,你可能會在 Logto 的管理控制台中找到你的客戶端憑證。)
客戶端憑證通常由兩個組成部分構成:
- 客戶端 ID:授權服務器分配給客戶端應用的一個唯一標識符。這是一個公有值,通常不被視為敏感。
- 客戶端密碼:僅客戶端和授權服務器知道的一個機密且安全存儲的值。它充當客戶端應用的身份驗證形式,並用於驗證客戶端在向授權服務器發出請求時的身份。
如你所見,客戶端 ID 和客戶端密碼的組合在令牌請求期間用於驗證客戶端並獲取訪問令牌。
客戶端憑證在確保 OAuth 流程的安全性方面發揮著重要作用。它們幫助授權服務器驗證客戶端應用的真實性並控制對受保護資源的訪問。安全地處理客戶端憑證並保護它們不被未經授權訪問顯得尤為重要。Logto 將客戶端應用按兩個不同的安全級別分類:
- 保密性客戶端: 這些包括服務器渲染的 Web 應用和機器到機器 (M2M) 應用。在保密性客戶端的情況下,所有授權相關的憑證,包括客戶端憑證,都在服務器端安全存儲。此外,所有中間交換請求均加密以確保數據的機密性。對於保密性客戶端,客戶端憑證洩露的風險非常低,因此它們被默認視為更安全的。=> 在令牌交換流程中,提供客戶端密碼是必須的。
- 公共客戶端: 這些包括單頁 Web 應用 (SPA) 和原生應用。對於公共客戶端,客戶端憑證通常在客戶端代碼中硬編碼,例如在 JavaScript 包或原生平台中的應用包中。由於客戶端憑證在客戶端代碼 中的固有暴露,憑證洩露的風險比保密性客戶端高。在令牌交換流程中,提供客戶端密碼是可選的。Logto 默認不會信任來自公共客戶端的這些憑證。
狀態
在 OAuth 流程中,state
參數是一個隨機生成的值,它被包含在客戶端發送至授權服務器的授權請求中。其目的是保持授權過程中客戶端請求的狀態或上下文。
state
參數作為一種安全措施來防止 跨站點請求偽造 (CSRF) 攻擊。當授權服務器在身份驗證和授權後將用戶重定向回客戶端應用時,它會在響應中包含相同的 state 值。客戶端應用必須將此值與它在授權請求中發送的原始 state
值進行比較。
通過驗證 state 參數,客戶端可以確保從授權服務器收到的響應與其發出的初始請求相符。這有助於防止攻擊者試圖誤導客戶端接受為另一用戶或應用程式的響應。
以下是虛構用例中的 CSRF 攻擊示例:
CSRF 攻擊:欺詐綁定社交帳戶 - 問題
通過適當的狀態驗證機制,客戶端可以檢測攻擊並防止用戶被重定向到攻擊者的網站:
CSRF 攻擊:欺詐綁定社交帳戶 - 解決方案
PKCE
如前所述,公共客戶端(如 SPA Web 應用和原生應用)承擔著更高的驗證憑證洩露風險,包括授權服務器發放的授權碼。
PKCE 代表 代碼交換證明密鑰。這是對 OAuth 2.0 授權碼流程 的擴展,旨在增強公共客戶端的安全性。
PKCE 是為了減少攻擊者攔截授權碼並在客戶端不知情的情況下將其交換為訪問令牌的風險。這種類型的攻擊稱為授權碼攔截攻擊,在客戶端應用無法安全存儲客戶端密碼的環境中更為普遍。
要實現 PKCE,客戶端應用生成隨機代碼驗證器並使用特定哈希算法(通常是 SHA-256)從中派生代碼挑戰。代碼挑戰包含在發送到授權服務器的初始授權請求中。
當授權服務器發出授權碼時,客戶端應用在令牌請求中包含原始代碼驗證器。服務器驗證代碼驗證器是否與存儲的代碼挑戰匹配,並僅在這時候發放訪問令牌。
通過使用 PKCE,客戶端應用確保授權碼本身不足以獲取訪問令牌。這一機制為授權流程增加了額外的安全層,尤其是對於無法安全存儲客戶端密碼的公共客戶端。
Logto 使用 PKCE 作為所有公共客戶端類型應用的唯一授權流程。不過,對於保密性客戶端,PKCE 可以省略。
重定向 URI
重定向 URI(統一資源標識符) 是在 OAuth 中身份驗證和授權過程後,授權服務器將用戶重定向回特定端點或 URL。
在 OAuth 流程期間,客戶端應用會包含重定向 URI 作為初始授權請求的一部分。此 URI 作為回調 URL,當用戶成功驗證身份並授權客戶端後用戶將被重定向到此處。
用戶完成身份驗證過程後,授權服務器會生成包含授權碼的響應,並將用戶重定向回指定的重定向 URI。
重定向 URI 的驗證是確保 OAuth 流程安全性和完整性的重要步驟。它涉及確認授權請求中使用的重定向 URI 和後續重定向是否有效和受信任。
讓我們回頭看看原始的 OAuth 漏洞報告。(以下部分參考自原帖](https://salt.security/blog/a-new-oauth-vulnerability-that-may-impact-hundreds-of-online-services))
當用戶使用 Expo Go 中的移動 APP 點擊 “login with facebook” 時,它會將用戶重定向到以下鏈接:
https://auth.expo.io/@moreisless3/me321/start?authUrl=https://www.facebook.com/v6.0/dialog/oauth?code_challenge=...&display=popup&auth_nonce=...&code_challenge_method=S256&redirect_uri=https://auth.expo.io/@moreisless3/me321&client_id=3287341734837076&response_type=code,token&state=gBpzi0quEg&scope=public_profile,email&returnUrl=exp://192.168.14.41:19000/--/expo-auth-session
在回應中,auth.expo.io 設置了以下 cookie: ru=exp://192.168.14.41:19000/--/expo-auth-session. 在第 5 步中,RU 值將用作返回 URL。然後它向用戶顯示確認消息,如果用戶批准 - 它將用戶重定向到 Facebook 登錄以繼續身份驗證流程
…
此頁面讀取查詢參數 “returnUrl” 並據此設置 cookie。
讓我們將 returnUrl 更改為
hTTps://attacker.com
(不允許 https,因此我嘗試插入大寫字母,並且有效),這導致 RU(返回 URL)被設置在 cookie 中為https://attacker.com
。…
在上述情況中,Expo 引入了一個名為 returnUrl 的新參數而忽視了原始的 redirect_uri
參數而疏於適當驗證。這一過失為攻擊者提供了一個機會來獲取 Facebook 返回的授權碼。欲了解詳情,請參閱原帖。
重定向 URI 驗證有幾個重要目的:
- 防止釣魚攻擊:通過驗證重定向 URI,授權服務器確保用戶被重定向回信任和授權的端點。這有助於防止攻擊者將用戶重定向到惡意或未經授權的位置。
- 保護免受開放重定向攻擊:開放重定向是可以被攻擊者利用將用戶重定向到惡意網站的漏洞 。通過驗證重定向 URI,授權服務器可以確保重定向在授權域名或信任域名範圍內進行。
- 確保授權響應正確路由:驗證重定向 URI 有助於保證授權服務器將用戶重定向回預期的客戶端應用。它確保響應(例如授權碼或訪問令牌)傳送到正確的目的地。
在 Logto 中,redirect_uri
註冊是所有類型應用的必需步驟。我們會將收到的值與 Logto 服務器中註冊的值進行比較和匹配。這包括任何自定義搜索參數。如果授權請求由於丟失、無效或不匹配的 redirect_uri
值而未通過驗證,將向註冊在文件上的 redirect_uri
返回無效的重定向 URI 錯誤。
總結
由於其複雜和微妙的性質,這些細節往往容易被忽視。有些只是像 state
這樣的隨機字符串。
然而,值得注意的是,這些安全措施為用戶授權增加了保護層,減少了如 CSRF 攻擊、授權碼攔截和未授權重定向等風險。
這些只是 OAuth 協議提供的全面安全功能的一小部分。OAuth 提供了一個強大的框架,用於安全的身份驗證和授權。它還提供靈活和開放的端點,以滿足現實世界產品應用中的各種需求。
作為開發人員和服務提供商,我們有必要持續關注用戶授權流程的安全性。保持警覺,遵循最佳實踐,並了解 OAuth 生態系統中的最新發展是確保用戶身份和敏感數據完整性和保護的關鍵。我們將堅持在 OAuth 的實施過程中遵守最高的安全標準,並保護用戶的隱私和信任。