正确比较 code_verifier 和 Java 中的 code_challenge
Correctly compare code_verifier with code_challenge in Java
我正在使用 passport-oauth2(passportjs.org 和 https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js)在 nodejs 应用程序中集成 OAuth2+PKCE。
它验证的后端写在Java。
问题是我似乎无法解码->散列 code_verifier 以正确匹配来自 passport-oauth2 的 code_challenge。
我知道来自 passport 的 Base64 编码已经生成 URL 安全(无填充,无包装,替代 +
或 /
),所以我我正在使用 Url 解码器:
Base64.getUrlDecoder().decode(...)
然后我使用 commons DigestUtils
生成解码验证器的 SHA256 并将其与挑战进行比较。所以整个事情看起来像这样:
java.util.Base64.Decoder decoder = java.util.Base64.getUrlDecoder();
String codeChallenge = // get the code challenge from my cache
byte[] decodedCodeChallenge = decoder.decode(codeChallenge);
byte[] decodedCodeVerifier = decoder.decode(codeVerifier);
if (!Arrays.equals(sha256(decodedCodeVerifier), decodedCodeChallenge)) {
return Response.status(400).entity(ERROR_INVALID_CHALLENGE_VERIFIER).build();
}
示例:
此代码验证者:5CFCAiZC0g0OA-jmBmmjTBZiyPCQsnq_2q5k9fD-aAY
应该匹配这个代码挑战:Fw7s3XHRVb2m1nT7s646UrYiYLMJ54as0ZIU_injyqw
一旦两者都被 Base64-url-解码并且验证者已经被 SHA256 散列,但它没有。
我做错了什么?
仅仅 5 分钟后我就想通了。
在passport-oauth2中,code verifier是Base64-url-encoded(random bytes)
:
verifier = base64url(crypto.pseudoRandomBytes(32))
参见:https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L236
接下来的挑战是 Base64-url-encoded(sha256(verifier))
,扩展为 Base64-url-encoded(sha256(Base64-url-encoded(random bytes)))
:
challenge = base64url(crypto.createHash('sha256').update(verifier).digest());
参见:https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L242
所以为了验证,我不需要解码任何东西。它处于编码状态 sha256
-d。
这最终奏效了:
java.util.Base64.Encoder encoder = java.util.Base64.getUrlEncoder();
String codeChallenge = // get code challenge from my cache;
String encodedVerifier = new String(encoder.encode(sha256(codeVerifier))).split("=")[0]; // Remember to remove padding
if (!encodedVerifier.equals(codeChallenge)) {
return Response.status(400).entity(ERROR_INVALID_CHALLENGE_VERIFIER).build();
}
我正在使用 passport-oauth2(passportjs.org 和 https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js)在 nodejs 应用程序中集成 OAuth2+PKCE。
它验证的后端写在Java。
问题是我似乎无法解码->散列 code_verifier 以正确匹配来自 passport-oauth2 的 code_challenge。
我知道来自 passport 的 Base64 编码已经生成 URL 安全(无填充,无包装,替代 +
或 /
),所以我我正在使用 Url 解码器:
Base64.getUrlDecoder().decode(...)
然后我使用 commons DigestUtils
生成解码验证器的 SHA256 并将其与挑战进行比较。所以整个事情看起来像这样:
java.util.Base64.Decoder decoder = java.util.Base64.getUrlDecoder();
String codeChallenge = // get the code challenge from my cache
byte[] decodedCodeChallenge = decoder.decode(codeChallenge);
byte[] decodedCodeVerifier = decoder.decode(codeVerifier);
if (!Arrays.equals(sha256(decodedCodeVerifier), decodedCodeChallenge)) {
return Response.status(400).entity(ERROR_INVALID_CHALLENGE_VERIFIER).build();
}
示例:
此代码验证者:5CFCAiZC0g0OA-jmBmmjTBZiyPCQsnq_2q5k9fD-aAY
应该匹配这个代码挑战:Fw7s3XHRVb2m1nT7s646UrYiYLMJ54as0ZIU_injyqw
一旦两者都被 Base64-url-解码并且验证者已经被 SHA256 散列,但它没有。
我做错了什么?
仅仅 5 分钟后我就想通了。
在passport-oauth2中,code verifier是Base64-url-encoded(random bytes)
:
verifier = base64url(crypto.pseudoRandomBytes(32))
参见:https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L236
接下来的挑战是 Base64-url-encoded(sha256(verifier))
,扩展为 Base64-url-encoded(sha256(Base64-url-encoded(random bytes)))
:
challenge = base64url(crypto.createHash('sha256').update(verifier).digest());
参见:https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L242
所以为了验证,我不需要解码任何东西。它处于编码状态 sha256
-d。
这最终奏效了:
java.util.Base64.Encoder encoder = java.util.Base64.getUrlEncoder();
String codeChallenge = // get code challenge from my cache;
String encodedVerifier = new String(encoder.encode(sha256(codeVerifier))).split("=")[0]; // Remember to remove padding
if (!encodedVerifier.equals(codeChallenge)) {
return Response.status(400).entity(ERROR_INVALID_CHALLENGE_VERIFIER).build();
}