【问题标题】:JJWT generated token has an invalid signatureJJWT 生成的令牌具有无效的签名
【发布时间】:2016-12-20 17:06:33
【问题描述】:

我正在使用 JJWT 库生成我的 JWT 令牌。我按如下方式生成我的令牌。我使用虚拟值作为我的密钥。

我们可以假设jwt.security.key=security-key

   @Value("${jwt.security.key}")
    private String key;

    @Value("${ws.issuer}")
    private String issuer;

    static final long ONE_MINUTE_IN_MILLIS=60000;

    static final long TOKEN_DURATION_IN_MIN=30L;

    private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    @Override
    public String issueToken(String userName) {

        long nowMillis = System.currentTimeMillis();
        long expMillis = nowMillis + (ONE_MINUTE_IN_MILLIS * TOKEN_DURATION_IN_MIN);

        return  Jwts
                .builder()
                .setId("01")
                .setIssuedAt(new Date(nowMillis))
                .setHeaderParam("typ","JWT")
                .setSubject(userName)
                .setIssuer(issuer)
                .setExpiration(new Date(expMillis))
                .signWith(signatureAlgorithm, key).compact();

    }

虽然令牌可以成功解码。每次我从 jwt.io 调试器验证它的签名时,它总是导致签名无效。可以看到here

【问题讨论】:

  • 您是否尝试在“解码”选项卡的“验证签名”中设置用于对令牌进行编码的密码?它应该这样工作。要验证 JWT,您需要知道秘密,只有客户端应该假设正文是正确的。
  • 我认为验证器被 jwt.io 破坏了(显然仍然如此)。绕过他们的验证检查,并在我的应用程序中这样做证明我的密钥正确验证。

标签: java jwt json-web-token jjwt


【解决方案1】:

security-key 不是有效的 Base64 编码字符串。阅读 JavaDoc 和 signWith(SignatureAlgorithm, String) 方法的参数名称:

/**
 * Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
 * 
 * <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
 * byte array is used to invoke {@link #signWith(SignatureAlgorithm, byte[])}.</p>
 *
 * @param alg                    the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS.
 * @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signing key to use to digitally sign the
 *                               JWT.
 * @return the builder for method chaining.
 */
JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey);

此外,为什么不考虑jwt.io 可能会损坏?它不是一个权威的 jwt 工具。

最后,我要注意的是,您永远不应该使用纯文本字符串或随机字符串作为签名密钥。数字签名始终使用字节数组计算。如果您希望密码术是安全的,您应该始终为您正在使用的签名算法使用足够长度的安全随机字节数组。

看看 JJWT 的Keys.secretKeyFor 方法生成足够长且足够强的密钥。

jwt.io 网站具有误导性,因为它没有使这一点显而易见,并暗示您可以使用任何旧字符串作为签名密钥。虽然 技术上 是可能的,但您绝对不应该这样做。如果需要将它们表示为字符串,则应始终使用经过 Base64 编码的安全随机字节数组。这就是为什么 JJWT 接受 String 作为键的方法假定它是 Base64 编码的 - 因为如果不是,您可能使用了无效或格式错误的键。

【讨论】:

  • 不看文档是我的错。使用 MacProvider.generateKey,生成密钥后,我必须使用 Base64 对其进行编码吗?然后将其传递给signWith?
  • TextCodec.BASE64.encode(key.getEncoded()); 但请注意:生成的 Base64 编码字符串,虽然您可以将其传递给 JJWT,但 被认为是加密的(只是从字节转换为字符串)。您应该在存储之前保持字符串安全和/或对其进行加密。
  • 最后一个问题,我创建了要点,以便澄清您的 cmets。 gist.github.com/kyeljmd/a68567680787e0d0eeef137479cd85aa 根据我给出的要点,变量 base64EncodeKey,我应该加密它/保持安全吗?这个 JWT 的接收者将如何检查令牌是否有效?
  • 另外,您能否将我发布到正确使用 JJWT 使用/生成密钥的正确方向
  • 你的要点在我看来不错。是的,您应该加密和/或保护生成的 Base64 编码字符串。
猜你喜欢
  • 2019-08-11
  • 2019-12-09
  • 2017-03-20
  • 2019-07-14
  • 2014-05-31
  • 1970-01-01
  • 2022-12-05
  • 2018-11-27
  • 2021-06-21
相关资源
最近更新 更多