OAuth 2.0 標準流程
在標準的 OAuth2.0 流程中,總共有 4 個角色:
- Resource owner: 就是我,我擁有使用者的資訊
- Client: Web Application,嘗試存取使用者資訊的人
- Authorization server: Google,給予 准許使用 的 Server
- Resource server: Google Contact API,存著我們的 resource 的人 ( 有時候 Resource Server 會跟 Authorization 一樣 )
這邊也提供一些其他名詞解釋
- Authorization grant: 證明了使用者真的有點下去 Yes
- Redirect URI: Authorization Server 要傳回給 Client 的地方
- Access Token: Client 會用這把 Access Token 當作 Key 去存取資源
而流程是:
- Client 給 Authorization Server Redirect URI + Resource Type: Code
- Client 在 Authorization Server 登入帳號密碼後,並給予 Authorization Server Grant 授權 ( Delegated )
- Authorization Server 把 Authorization Code 透過 Callback URL (redirect url)
- Client 連上了 Callback url 後,也就把相關資訊 ( Authorization Code ) 給予了我們的 Application
- Client 再把 Authorization Code 傳回去給 Authorization Server 交換真正需要用到的 Access Token
- Client 可以快快樂樂地拿 Access Token 去 Resource Server 取資料惹
為什麼會需要 PKCE
光是這樣的流程看起來很安全也很好用呀 利用 Authorization Code 去交換 Access Token 而不是在 Front Channel (可以想像成是「資料可以被使用者知道的路徑」) 這樣很 OK 呀!
為什麼需要另外一個協議呢?
因為這段流程是假設此 Client 是一個 Backend Application 但是我們在現實社會中,常常會需要開發 Desktop Application,也就是說整個流程和系統中,並沒有 Back Channel,整個系統的資料流都是可以被使用者端取得的,也就代表駭客有機會竊取 Authorization Code 並換取 Access Token! 註:PKCE 現在已經被建議用於所有公共客戶端,包括 SPA(單頁應用)和 Mobile 應用。
除此之外,要將 Authorization Code 交換取得 Access Token 的時候,要在 API 中帶上 Client Secret 才可以,但是如果是 Desktop Application 的話,把 Client Secret 編譯在其中是一件非常不智的行為!
也正因為如此,我們需要另一個全新的協議流程來保護我們取得 Access Token!
鄭重介紹我們今天的主角:“Proof Key for Code Exchange” (PKCE,發音為 “pixy”)
PKCE 是為了解決「在不把 Client Secret 暴露在使用者端」的情況下與 Resource Authorizator 交換資訊已取得 Access Token,更重要的是可以防止攔截攻擊等資安問題!
PKCE 流程
首先,我們先定義一下名詞。
- Application: Desktop Application,也就是我們常使用的桌面應用軟體,像是 Slack 或是 VSCode 等等。
完整的 PKCE 流程應該會是:
- Application 端初始化
- Application 端在 記憶體內 (InMemory) 建立一組隨機亂碼字串,我們稱為「
Code Verifier
」 - Application 端在 記憶體內 (InMemory) 利用 SHA-256 hash
Code Verifier
並得到一組更短的字串,再進行 Base64 URL 安全編碼(Base64 URL-encoded)後,我們稱為「Code Challenge
」 - 將
Code Verifier
保存在記憶體內 (InMemory) 以供後續驗證使用
- Application 端在 記憶體內 (InMemory) 建立一組隨機亂碼字串,我們稱為「
- 授權請求
- 當 Application 端取得登入頁面時,將額外的兩個參數帶入網址列中
- code_challenge:由
Code Verifier
生成的挑戰碼 - code_challenge_method:之前用來生成挑戰碼的方法,一般為 “S256”(代表 SHA-256)
- code_challenge:由
- 當 Application 端取得登入頁面時,將額外的兩個參數帶入網址列中
- 用戶授權
這步驟與一般的 OAuth2.0 一樣,要取得使用者的
Grant
- 授權碼(Authorization Code)返回
- Authorization Code 一樣會返回到使用者,此時一樣會有被駭客攔截的可能
- 但是不一樣的是,下一步驟!
- Token 請求
- 要將 Authorization Code 交換 Access Token 的時候要把 「
Code Verifier
」帶上,交由 Authorization Server 判斷是否是相同來源。 - 此時駭客就不知道我們放在 記憶體內 (InMemory) 的
Code Verifier
具體數值,也就讓駭客無法偽造我們的身份取得 Access Token
- 要將 Authorization Code 交換 Access Token 的時候要把 「
- Authorization Server 驗證
- Authorization Server 會將
Code Verifier
經由code_challenge_method
處理後與剛剛傳送得 code_challenge 比對 - 成功之後才回傳 Access Token
- Authorization Server 會將
- Token 返回
- Application 端順利取得 Access Token
安全性提升在哪裡了?
PKCE 的最重要的作用:
- 保護授權碼:即使攻擊者攔截授權碼,沒有
Code Verifier
也無法使用授權碼獲取令牌。 - 改進安全性:即使在沒有機密客戶端環境的情況下(如移動和 Web 應用),PKCE 也能為授權碼模式提供更強的安全性。
如果把傳統的 OAuth2.0 的 client secret 編譯在應用程式中的話,這類型的字串是很容易(非常容易)的就可以使用反解譯的手法就可以取得了! 相較於 PKCE,PKCE 使用隨機碼 ( 一次性隨機值 ) 和 hash ( 驗證來源 ) 的方式並且一切資訊都暫存在記憶體中,這種手法會更不容易的被竊取
流程中就算 Code Challenge
被攔截竊取了,攻擊者也無法透過逆推的方式推算出 code verifier
就算可以推算出來,時效性也已經過期了!
完美!
總結
此篇為介紹最重要的主角:PKCE,的整體流程以及此協議解決了什麼樣的難題,PKCE 協議解決了 OAuth 2.0 在 Desktop Application 中的安全問題,提升了整體安全性。它現已被建議用於所有公共客戶端,包括單頁應用和移動應用,以提供更強的安全保護。
下一篇我們來介紹 AWS Cognito User Pool 是如何支援 PKCE 的!