使用 Amazon AWS Cognito `.well-known/jwks.json` 数据无法对某些字段进行 base64 解码
Using Amazon AWS Cognito `.well-known/jwks.json` data fails to base64 decode some fields
使用 Amazon AWS Cognito Federated Identities 并解析数据时:
https://cognito-identity.amazonaws.com/.well-known/jwks_uri
看起来像:
{"keys":[
{"kty":"RSA",
"alg":"RS512",
"use":"sig",
"kid":"ap-northeast-11",
"n":"AI7mc1assO5n6yB4b7jPCFgVLYPSnwt4qp2BhJVAmlXRntRZ5w4910oKNZDOr4fe/BWOI2Z7upUTE/ICXdqirEkjiPbBN/duVy5YcHsQ5+GrxQ/UbytNVN/NsFhdG8W31lsE4dnrGds5cSshLaohyU/aChgaIMbmtU0NSWQ+jwrW8q1PTvnThVQbpte59a0dAwLeOCfrx6kVvs0Y7fX7NXBbFxe8yL+JR3SMJvxBFuYC+/om5EIRIlRexjWpNu7gJnaFFwbxCBNwFHahcg5gdtSkCHJy8Gj78rsgrkEbgoHk29pk8jUzo/O/GuSDGw8qXb6w0R1+UsXPYACOXM8C8+E=",
"e":"AQAB"},
... }
这可以很好地解码 n
字段使用此代码(Kotlin 调用 JDK 8 Base64 class):
Base64.getDecoder().decode(encodedN.toByteArray())
但是当使用 Cognito 用户池 时,它在 URL 处的数据格式为:
https://cognito-idp.${REGION}.amazonaws.com/${POOLID}/.well-known/jwks.json
它有相同类型的数据,但不会解码。相反,我最终遇到如下错误:
Illegal base64 character 5f
因为那是下划线 _
并且在 Base64 URL 字母表中,我尝试将解码更改为:
Base64.getUrlDecoder().decode(encodedN.toByteArray())
但随后第一组数据不再正确解码,因为它包含 /
和其他 Base64 URL 编码的无效字符。
有没有一种方法可以用同一个解码器处理这两个 jwks
组数据?!?
注: 这个问题是作者(Self-Answered Questions)特意写的,所以有兴趣的问题的解决办法都在SO里分享.
问题是 Amazon AWS Cognito 团队对基本相同的事物使用了两种不同的 Base64 编码字母表。所以你需要检测正在使用的是哪个。
如果编码后的字符串以=
结尾或包含+
或/
则肯定是正常的Base64.getDecoder()
。如果它包含 -
或 _
那么它肯定是 Base64.getUrlDecoder()
。否则没有什么特别的,最好使用 Base64.getUrlDecoder()
因为你不知道长度是否需要填充。
这转换为(在 Kotlin 中,但逻辑上适用于任何语言):
fun base64SafeDecoder(encoded: String): ByteArray {
val decoder = if (encoded.endsWith('=') || encoded.any { it == '+' || it == '/' }) {
Base64.getDecoder()
}
else {
Base64.getUrlDecoder()
}
return decoder.decode(encoded.toByteArray())
}
对于任何具有 Base64 解码的语言来说,这都是一个问题,因为它们可能会松散并忽略无效字符(有些会),或者它们可能会很严格并引发异常。一些 Base64 encoding/decoding 测试网站也表现出这两种行为,静默忽略无效字符是危险的。稍后使用解码结果会出现错误。
您可以尝试使用 Base64 解码的 apache 变体 (org.apache.commons.codec.binary.Base64)。
decodeBase64(String base64String) 方法无缝处理 base64 和 base64 url 安全编码。并且 isBase64 方法提供了一个检查来检测字符串是否以 base64 或 base64 编码 url 安全。
使用 Amazon AWS Cognito Federated Identities 并解析数据时:
https://cognito-identity.amazonaws.com/.well-known/jwks_uri
看起来像:
{"keys":[
{"kty":"RSA",
"alg":"RS512",
"use":"sig",
"kid":"ap-northeast-11",
"n":"AI7mc1assO5n6yB4b7jPCFgVLYPSnwt4qp2BhJVAmlXRntRZ5w4910oKNZDOr4fe/BWOI2Z7upUTE/ICXdqirEkjiPbBN/duVy5YcHsQ5+GrxQ/UbytNVN/NsFhdG8W31lsE4dnrGds5cSshLaohyU/aChgaIMbmtU0NSWQ+jwrW8q1PTvnThVQbpte59a0dAwLeOCfrx6kVvs0Y7fX7NXBbFxe8yL+JR3SMJvxBFuYC+/om5EIRIlRexjWpNu7gJnaFFwbxCBNwFHahcg5gdtSkCHJy8Gj78rsgrkEbgoHk29pk8jUzo/O/GuSDGw8qXb6w0R1+UsXPYACOXM8C8+E=",
"e":"AQAB"},
... }
这可以很好地解码 n
字段使用此代码(Kotlin 调用 JDK 8 Base64 class):
Base64.getDecoder().decode(encodedN.toByteArray())
但是当使用 Cognito 用户池 时,它在 URL 处的数据格式为:
https://cognito-idp.${REGION}.amazonaws.com/${POOLID}/.well-known/jwks.json
它有相同类型的数据,但不会解码。相反,我最终遇到如下错误:
Illegal base64 character 5f
因为那是下划线 _
并且在 Base64 URL 字母表中,我尝试将解码更改为:
Base64.getUrlDecoder().decode(encodedN.toByteArray())
但随后第一组数据不再正确解码,因为它包含 /
和其他 Base64 URL 编码的无效字符。
有没有一种方法可以用同一个解码器处理这两个 jwks
组数据?!?
注: 这个问题是作者(Self-Answered Questions)特意写的,所以有兴趣的问题的解决办法都在SO里分享.
问题是 Amazon AWS Cognito 团队对基本相同的事物使用了两种不同的 Base64 编码字母表。所以你需要检测正在使用的是哪个。
如果编码后的字符串以=
结尾或包含+
或/
则肯定是正常的Base64.getDecoder()
。如果它包含 -
或 _
那么它肯定是 Base64.getUrlDecoder()
。否则没有什么特别的,最好使用 Base64.getUrlDecoder()
因为你不知道长度是否需要填充。
这转换为(在 Kotlin 中,但逻辑上适用于任何语言):
fun base64SafeDecoder(encoded: String): ByteArray {
val decoder = if (encoded.endsWith('=') || encoded.any { it == '+' || it == '/' }) {
Base64.getDecoder()
}
else {
Base64.getUrlDecoder()
}
return decoder.decode(encoded.toByteArray())
}
对于任何具有 Base64 解码的语言来说,这都是一个问题,因为它们可能会松散并忽略无效字符(有些会),或者它们可能会很严格并引发异常。一些 Base64 encoding/decoding 测试网站也表现出这两种行为,静默忽略无效字符是危险的。稍后使用解码结果会出现错误。
您可以尝试使用 Base64 解码的 apache 变体 (org.apache.commons.codec.binary.Base64)。
decodeBase64(String base64String) 方法无缝处理 base64 和 base64 url 安全编码。并且 isBase64 方法提供了一个检查来检测字符串是否以 base64 或 base64 编码 url 安全。