繁體中文(香港)
  • auth

什麼是 PKCE:從基本概念到深入理解

本文解釋了 PKCE(Proof Key for Code Exchange)如何通過防止惡意應用攔截授權碼來保護 OAuth 2.0 授權碼流程,帶你從基本概念到全面理解。

Yijun
Yijun
Developer

Stop wasting weeks on user auth
Launch secure apps faster with Logto. Integrate user auth in minutes, and focus on your core product.
Get started
Product screenshot

Proof Key for Code Exchange(PKCE)是授權碼流程的一個擴展,它最初是為了保護移動應用中的授權碼流程而設計的,現在也建議單頁應用使用。在 OAuth 2.1 中,PKCE 是對所有類型的客戶端強制執行的,包括公共客戶端機密(私有)客戶端

在本文中,我們將幫助你理解為什麼創建 PKCE 以及它如何保護你的應用,給你對 PKCE 的深刻理解。

為什麼需要 PKCE?

在 OAuth 2.0 授權碼流程中,用戶請求通過應用登入。驗證服務器將用戶導向驗證頁面。用戶驗證後,服務器返回授權碼給應用,然後應用使用該碼向驗證服務器請求訪問令牌。

這一流程存在顯著的安全風險:授權碼可能被惡意程序攔截。這在移動設備上尤其令人擔憂,因為其他應用可能註冊相同的重定向 URI 並攔截授權碼。

攔截過程如下圖所示:

步驟 (1):應用通過不能被攔截的安全 API 執行授權請求。在這步驟中,請求者還提供了一個重定向 URI。

步驟 (2):請求隨後被轉發給 OAuth 2.0 授權服務器。因為 OAuth 要求使用 TLS,這些通信受到 TLS 保護,不能被攔截。

步驟 (3):授權服務器返回授權碼。

步驟 (4.a): 授權碼通過在步驟 (1) 中提供的重定向 URI 被返回給請求者。在這一步中,如果惡意應用註冊自己為該重定向 URI 的處理程序,則惡意應用可以攔截授權碼。有了授權碼,攻擊者可以在步驟 (5.a) 和 (6.a) 中請求並獲取訪問令牌。

如上所示,在 OAuth 2.0 授權碼流程中,如果授權碼被攔截,攻擊者可以利用它來獲取訪問令牌。因此,我們需要一個機制來防止授權碼攔截,這導致了 PKCE 的創立。

PKCE 如何運作?

如上所述,如果我們想要防止被攻擊,我們需要確保只有發起請求的應用可以請求和獲取訪問令牌。這就是 PKCE 發揮作用的地方。

PKCE 通過引入「驗證密鑰」概念來解決這個問題。

在請求授權碼時,應用首先生成一個隨機的驗證碼並將其存儲在本地。然後,它使用特定算法將這個驗證碼轉換成驗證挑戰。應用在授權碼請求期間將驗證挑戰和驗證挑戰方法一併發送給驗證服務器。

驗證碼是一個隨機生成的字符串,驗證挑戰通過轉換驗證碼得來。支持兩種轉換方法:

  • plain:直接使用驗證碼作為驗證挑戰
  • S256:對驗證碼應用 SHA-256 雜湊,隨後再進行 Base64URL 編碼。由於雜湊輸出不能逆向獲得驗證碼,且由於 plain 方法在傳輸過程中可能會受到中間人攻擊的威脅,出於安全考慮,強烈建議使用 S256

用戶驗證後,驗證服務器將授權碼返回給應用。在請求訪問令牌時,應用將授權碼和驗證碼一併發送到驗證服務器。服務器使用先前接收到的「驗證挑戰方法」轉換「驗證碼」,並將結果與先前收到的「驗證挑戰」進行比較,以驗證客戶端對「驗證碼」的擁有權。

步驟 (1-3):應用創建並記錄一個名為「驗證碼」的秘密,並衍生出一個轉換版本「驗證挑戰」,在 OAuth 2.0 授權請求中與轉換方法「驗證挑戰方法」一起發送。

步驟 (3-6):授權服務器照常回應,但記錄「驗證挑戰」和「驗證挑戰方法」。

步驟 (7.a):應用然後將授權碼照常發送至令牌端點,但包括在步驟 (1) 生成的「驗證碼」秘密。

步驟 (8.a-9.a):授權服務器將「驗證碼」轉換為「驗證挑戰」,並將其與步驟 (1-3) 中的「驗證挑戰」比較。如果它們不相等,則拒絕訪問。

在這種情況下,即使惡意應用攔截了步驟 (6.b) 的授權碼,由於它不擁有「驗證碼」秘密,並且因為「驗證碼」是通過 TLS 傳輸的,無法被攔截,所以無法將其兌換為訪問令牌。

總結

本文闡述了 PKCE 如何運作及其為何必要於保護授權碼流程。通過增加驗證密鑰機制,PKCE 防止惡意應用攔截和濫用授權碼。希望這個解釋能幫助你深入理解 PKCE。