使用带有 RSA 的 JWT 解码 Id 令牌

Posted

技术标签:

【中文标题】使用带有 RSA 的 JWT 解码 Id 令牌【英文标题】:Decode IdToken using JJWT with RSA 【发布时间】:2018-07-26 20:34:29 【问题描述】:

我的客户向我发送了一个 JWT,我需要使用他们的公钥验证这个 JWT。 我正在使用 Java 和 JJWT 框架来验证这个令牌。 我知道使用 HS256 解码此令牌,但使用 RS256 我不知道。

他们的配置是:

在此处编辑以改进我的问题。 我正在使用的 jjwt 解析示例:

        Claims String secret = "-----BEGIN CERTIFICATE-----myx5ckey-----END CERTIFICATE-----"
    byte[] dataBytes = Base64.getEncoder().encode(secret.getBytes());
    byte[] byteKey = Base64.getDecoder().decode(dataBytes);
    X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
    KeyFactory kf = KeyFactory.getInstance("RSA");

    PublicKey publicKey = kf.generatePublic(X509publicKey);

    Claims body = null;
    body = Jwts.parser().setSigningKey(publicKey.getEncoded())
            .parseClaimsJws(idToken)
            .getBody();


java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

    at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)

如何使用我显示的 JWKS 信息验证收到的令牌? (上图)

【问题讨论】:

【参考方案1】:

我解决了我的问题。

String secret2 = "myX5c";
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate certificate = cf.generateCertificate(new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(secret2)));
        PublicKey publicKey = certificate.getPublicKey();


        Claims body = null;
        body = Jwts.parser().setSigningKey(publicKey)
                .parseClaimsJws(idToken)
                .getBody();

@KcDoD 感谢您的提示。

【讨论】:

【参考方案2】:

tldr;需要遵循三个步骤

    从JWK 提取公钥可能会通过发现文档或任何其他方式。 提取 JWS 签名和 JWS 签名输入,如 JWS specification 所述 将公钥、JWS 签名和 JWS 签名输入传递给签名验证者

根据库的不同,第 2 步和第 3 步可以一步完成。!

长答案

要验证您必须遵循 JWS 规范。

RFC7515 中定义的 JWS 规范解释了如何创建验证令牌所需的 JWT 的 MAC。协议的Appendix 2 解释了如何使用 RS256 创建 MAC 并对其进行验证。

使用发现信息,您必须识别公钥。现在,您已经收到了JWK 的关键详细信息。根据x5x上的JWK协议定义,

“x5c”(X.509 证书链)参数包含一个链 或多个 PKIX 证书

所以基本上你在 JWK 中有公钥。现在您需要将 x5x 的编码字符串转换为公钥。为此,请检查已回答的question。

一旦构造了公钥,就可以使用它来验证令牌。以下是从规范中提取的内容。

A.2.2. Validating

由于“alg”标头参数是“RS256”,我们验证 JWS 中包含的 RSASSA-PKCS1-v1_5 SHA-256 数字签名 签名。

验证 JWS 签名与前面的示例有些不同。我们传递公钥 (n, e)、JWS 签名(它是从 JWS 表示中编码的值解码的 base64url)和 JWS 签名输入(它是 JWS 紧凑序列化表示的初始子字符串,直到但不是包括第二个句点字符)到已配置为使用 SHA-256 哈希函数的 RSASSA-PKCS1-v1_5 签名验证器。

要验证,最好使用库。作为参考,这里是一个使用nimbus完成的链接

【讨论】:

嗨@KcDoD,我读了你的解释,帮助很大,但我不能解决我的问题。 @javaTry 告诉我你的问题

以上是关于使用带有 RSA 的 JWT 解码 Id 令牌的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 RS256 加密的 express-jwt 在应用程序路由上解码 JWT 令牌会引发未经授权的错误

ruby-jwt编码,用RS256算法解码

django rest框架使用jwt RS256解码签名错误

使用密钥大小小于2048的RSA安全密钥创建JWT令牌时出错

如何使用 jwt 令牌获取用户 ID

如何使用 jwt 令牌获取用户 ID