這些OAuth2客戶端的認證方式你未必瞭解

碼農小胖哥發表於2022-03-28

OAuth2客戶端按照它們與授權伺服器進行安全認證的能力可以分為機密型別(Confidential)和公共型別(Public)。

機密型別的自身會有個密碼憑據,比如Web伺服器後端程式;而公共型別則沒有密碼憑據,純瀏覽器前端應用或者移動客戶端應用大都屬於這一種型別。不管是哪一種,它們都有客戶端ID(client_id)。

OAuth2客戶端認證

客戶端在執行OAuth2授權的敏感流程中(相關的流程有令牌請求、令牌自省請求、令牌撤銷請求)必須使用授權伺服器進行客戶端身份驗證,確保客戶端中途不會被調包。

客戶端認證方式

目前客戶端認證的方式有以下幾種:

前面GiteeDEMO使用的是過時的POST方式;微信DEMO使用的是非OAuth2標準的方式;Spring Authorization Server目前相關的DEMO使用的是client_secret_basic方式。剩下的方式中client_secret_jwtprivate_key_jwt用的比較多,這兩種方式可以很好地保護客戶端的認證資訊,安全性更高。Spring SecuritySpring Authorization Server目前已經支援這兩種方式。

client_secret_jwt

client_secret_jwt方式是OAuth2客戶端將自己的金鑰作為HmacSHA256演算法的key生成SecretKey

byte[] pin = clientSecret.getBytes(StandardCharsets.UTF_8);
SecretKeySpec  secretKey = new SecretKeySpec(pin,"HmacSHA256");

然後通過SecretKey生成一個攜帶OAuth2客戶端資訊的JWT,在授權碼請求Token環節攜帶該JWT以便授權伺服器進行客戶端認證,請求的報文為:

     POST /oauth2/token HTTP/1.1
     Host: oauth2_client.felord.cn
     Content-Type: application/x-www-form-urlencoded

     grant_type=authorization_code&
     code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&
     client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
     client_assertion=你的JWT

授權伺服器收到請求後通過OAuth2客戶端的client_secretJWT進行解碼校驗以認證客戶端。這種方式能很好的保護client_secret在非HTTPS環境下的傳輸。

這裡OAuth2客戶端的金鑰(client_secret)位元長度必須大於等於256

private_key_jwt

private_key_jwtclient_secret_jwt唯一的區別就是生成JWT的方式不同。通過這種方式,OAuth2客戶端已經不需要client_secret,只需要配置一對RSA或者EC金鑰,通過金鑰來生成JWT,另外還需要向授權伺服器提供公鑰,通常是一個jwkSetUrl。該方式的細節已經在OAuth2專欄JOSE規範一文中進行過詳細說明了,這裡不再贅述。這種方式讓客戶端的認證資訊更加安全的傳輸,是我個人比較喜歡的方式。

tls_client_auth

這個比較高階,嵌入了TLS安全層,在HTTP協議級別來認證OAuth2客戶端,它涉及的證照來自可信任的CA。這種方式基本脫離了應用層,是一種無侵入的方式。

self_signed_tls_client_auth

這個同樣也是在TLS安全層,不過它使用了自簽名的X.509證照。

總結

市面上的教程大多隻會提到過時的POST方式以及client_secret_basicclient_secret_post方式,對後面的五種則很少涉及,胖哥已經對private_key_jwtclient_secret_jwt進行了實現,詳細請訂閱我的Spring Security OAuth2專欄。這些OAuth2客戶端認證方式在不同的場景有不同的優勢,你可以根據不同的安全級別選擇不同的OAuth2客戶端認證方式。

關注公眾號:Felordcn 獲取更多資訊

個人部落格:https://felord.cn

相關文章