關於OAuth2.0 Authorization Code + PKCE flow在原生客戶端(Native App)下整合的一點思考

喬達摩(嘿~)發表於2022-03-22

Working with Proof Key for Code Exchange (PKCE) - DEV Community

寫在前面

前幾天看了園友的一篇文章被廣泛使用的OAuth2.0的密碼模式已經廢了,放棄吧 被再次提起: Implicit Flow Password Grant,均已被標記為Legacy,且OAuth2.1裡面已經刪除了,目前OAuth2.1只剩三種flow:

  • Authorization Code+ PKCE
  • Client Credentials
  • Device Code

作為完美踩坑ImplicitPassword 兩種flow的人,有點感慨,特來發表下自己的愚見;

並帶著以下問題:

  • 在SPA(單頁面應用程式Vue等)中不再用Implicit flow,還能用什麼?
  • 在Native App和小程式等Public Client中不再用Password flow,還能用什麼?

Implicit 和 Password 的問題

以下均為個人理解,不保證全對

Implicit的問題

  • 1、比較容易洩露access_token(下文簡稱token), 比如有的開發者條件不允許,web 服務用http的協議直接上生產(正確是一定要用https);
  • 2、token直接暴露在請求裡,如果token許可權不控制好的話使用者能輕而易舉呼叫不該有許可權的介面;

解決方案:

改為用 :Authorization Code + PKCE

Password的問題

園友已經說的很清楚了我總結下;

  • 1、最大的問題就是違背了委託授權的原則,比如我的Web服務用微信登入用的Password flow的話,那意思是需要在我的登入頁面裡面填寫微信的賬號和密碼,這眼見的不可思議和不合理吧;

我個人看法:

雖然目前OAuth2最佳實踐中已經明確要求不能使用這種模式,但是 原有已經使用是這種模式的自有App還是可以接著使用的 沒有問題;因為自有App和自有授權中心沒有需要授權,是一起的;

如果是新開發App呢,還是優先考慮:Authorization Code + PKCE,畢竟Password已經是過時的流程了;

思考Authorization Code+ PKCE在Native App使用的問題

先回顧Authorization code Flow

img

圖來自

回顧流程和請求

我這裡是web服務,用的是SPA的客戶端,授權服務用的是IdentityServer4;

假設授權服務是:https://localhost:44356/ 客戶端是:https://localhost:44357/

  • A、先判斷登入、未登入先引導使用者去授權伺服器授權(一般是開啟授權方登入頁面);

判斷登入

https://localhost:44356/connect/authorize?client_id=vuejs_code_client&redirect_uri=https%3A%2F%2Flocalhost%3A44357%2Fcallback.html&response_type=code&scope=openid profile dataEventRecords&state=10f308dbb5d54c01be3b97c495569e8c&code_challenge=gp1EWoH_KsIdL6sGyohEIR6815PcVmz05V_dYvPbafI&code_challenge_method=S256&response_mode=query

登入頁面

https://localhost:44356/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Dvuejs_code_client%26redirect_uri%3Dhttps%253A%252F%252Flocalhost%253A44357%252Fcallback.html%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520dataEventRecords%26state%3D10f308dbb5d54c01be3b97c495569e8c%26code_challenge%3Dgp1EWoH_KsIdL6sGyohEIR6815PcVmz05V_dYvPbafI%26code_challenge_method%3DS256%26response_mode%3Dquery

  • C、登入成功返回Authorization code;

登入成功回撥

https://localhost:44356/connect/authorize/callback?client_id=vuejs_code_client&redirect_uri=https%3A%2F%2Flocalhost%3A44357%2Fcallback.html&response_type=code&scope=openid profile dataEventRecords&state=10f308dbb5d54c01be3b97c495569e8c&code_challenge=gp1EWoH_KsIdL6sGyohEIR6815PcVmz05V_dYvPbafI&code_challenge_method=S256&response_mode=query

https://localhost:44357/callback.html?code=C0EF4B31E9F67481019DC51ED3F393264973027E0275644915314ED25F0F95B7&scope=openid profile dataEventRecords&state=10f308dbb5d54c01be3b97c495569e8c&session_state=j4dyIjlHucHYEHMrli0nBisCinR9Iq9gncp3khniF58.6A5CBF9592729E89570BE9FAC8A962DF

  • D、通過code去授權中心token endpoint換取token;

post 請求
https://localhost:44356/connect/token

ok,以上流程後拿到token後面的請求Resource Owner就沒問題了。

Authorization code Flow在Native App中使用有何問題

首先是Authorization code流程裡面的,code引數傳遞通過重定向的方式,在原生App裡一般這樣重定向一般有兩種方式:

  • 1、是繫結URL Scheme通過類似app-name://?code=的方法把code傳遞給原生客戶端;
  • 2、在本地起個HTTP伺服器通過http://localhost:port/?code=的方法監聽code

這兩種方式都有被第三方惡意應用佔用URL Scheme或者localhost埠擷取code的風險

另一個問題是,Authorization code code換取token的時候需要app_secret這些;

所以引出我們的PKCE流程;

Authorization Code**+ **PKCE在Native App中使用

img

PKCE在這篇文章裡面已經講得很清楚了,我簡單總結下:

上文我們已經清楚,Authorization code(簡稱code)流程裡面的,code傳遞給原生App的兩種方式都不安全,那麼引出PKCE的概念:

PKCE

全稱Proof Key for Code Exchange,直譯:用一個Proof key來做Code交換;

解決的問題是,既然你可以攔截我的Authorization code,那我再加一個我有,你沒有的引數(等於是票據、驗證憑據)做code交換條件就行;

PKCE步驟為:

  • 1、先隨機生成一串字串叫code_verifier
  • 2、用code_challenge_method方法(sha256等)把code_verifier加密成code_challenge
  • 3、把code_challengecode_challenge_method來發起授權請求,生成關聯這兩項值的code;
  • 4、用code和code_verifier去換取token;
  • 5、授權伺服器返回token,和refresh token(app這個很重要);

我們可以看到,因為我們的code已經關聯code_challengecode_challenge_method,即時攻擊者攔截了也沒用了,因為你沒有code_verifier,你同樣換不到token;;

最後,可以看到整個PKCE流程設計精妙,已經解決了Code傳參問題;

總結

有了PKCE, 在Native App中使用Code傳參的話直接用原先的方式:

  • 1、是繫結URL Scheme通過類似app-name://?code=的方法把code傳遞給原生客戶端;
  • 2、在本地起個HTTP伺服器通過http://localhost:port/?code=的方法監聽code

傳遞code就行;

另外還有一種方式,直接在Native App裡面嵌入Webview來傳遞,在攜帶code重定向這個步驟,攔截重定向url,獲取code,換取token;

現在我看到很多App都是這樣做的;

水完,over.

參考

https://www.cnblogs.com/felordcn/p/16011138.html

https://www.cnblogs.com/myshowtime/p/15555538.html

https://medium.com/oauth-2/why-you-should-stop-using-the-oauth-implicit-grant-2436ced1c926

相關文章