【问题标题】:JWT can not be decipher from keysJWT 无法从密钥中破译
【发布时间】:2021-12-20 02:38:57
【问题描述】:

创建了以下 JWT 密钥。 但是,我们想将 io.jsonwebtoken 升级到 0.11.2 并看到 signWithMethod 已被弃用。 将签名更改为密钥,但是,旧密钥与密钥解密不兼容...为什么,如何? 如果它破坏了已发布的密钥,则无法进入 prod。

       private final String secretKeyEncoded = Base64.getEncoder().encodeToString(secretKey.getBytes());


       Key key = new SecretKeySpec(secretKeyEncoded.getBytes(), SignatureAlgorithm.HS256.getJcaName());

        final String originalJWT = Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(validity)
                .signWith(SignatureAlgorithm.HS256, secretKeyEncoded)
                .compact();

        Jwts.parser().setSigningKey(secretKeyEncoded).parseClaimsJws(originalJWT);//old way
        Jwts.parserBuilder().setSigningKey(secretKeyEncoded).build().parseClaimsJws(originalJWT);
        Jwts.parserBuilder().setSigningKey(new String(key.getEncoded())).build().parseClaimsJws(originalJWT);
        Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(originalJWT);//!!!!!! THIS IS NOT WORKING
        final String newJWT = Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(validity)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();

        Jwts.parser().setSigningKey(key).parseClaimsJws(newJWT);//old way depricated
        Jwts.parserBuilder().setSigningKey(secretKeyEncoded.getBytes()).build().parseClaimsJws(newJWT);
        Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(newJWT); // THIS ONE WORKS !!!!

【问题讨论】:

    标签: java jwt


    【解决方案1】:

    signWith overload that takes a String 要求字符串包含实际密钥的 base64 编码,但其他重载(包括 Keybyte[])采用实际密钥而不是 base64 编码。这一点说得很清楚;你没读过javadoc吗? 此更正的代码使用 base64 用于 String 版本而不是 Key AND byte[] 版本适用于所有组合。

    static void SO69863437Jjwt (String[] args) throws Exception {
        final String secretKey = "thisisanicelongsecretkey12345678", // BAD IDEA: shouldn't be String
                secretKeyEncoded = Base64.getEncoder().encodeToString(secretKey.getBytes());
        final Date now = new Date(), validity = new Date(now.getTime()+86400000);
    
        Key key = new SecretKeySpec( //WRONG secretKeyEncoded.getBytes(), SignatureAlgorithm.HS256.getJcaName());
                secretKey.getBytes(), SignatureAlgorithm.HS256.getJcaName()); // NOT BASE64!
    
        @SuppressWarnings("deprecation")
        final String originalJWT = Jwts.builder() //.setClaims(claims)
                .setIssuedAt(now) .setExpiration(validity)
                .signWith(SignatureAlgorithm.HS256, secretKeyEncoded)
                .compact();
        //Jwts.parser().setSigningKey(secretKeyEncoded).parseClaimsJws(originalJWT);//old way
        Jwts.parserBuilder().setSigningKey(secretKeyEncoded).build().parseClaimsJws(originalJWT);
        //ONLY WORKED WITH WRONG Key Jwts.parserBuilder().setSigningKey(new String(key.getEncoded())).build().parseClaimsJws(originalJWT);
        Jwts.parserBuilder().setSigningKey(secretKey.getBytes()).build().parseClaimsJws(originalJWT); //BETTER
        Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(originalJWT);// NOW WORKS
    
        final String newJWT = Jwts.builder() //.setClaims(claims)
                .setIssuedAt(now) .setExpiration(validity)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
        //Jwts.parser().setSigningKey(key).parseClaimsJws(newJWT);//old way depricated
        //ONLY WORKED WITH WRONG Key Jwts.parserBuilder().setSigningKey(secretKeyEncoded.getBytes()).build().parseClaimsJws(newJWT);
        Jwts.parserBuilder().setSigningKey(secretKey.getBytes()).build().parseClaimsJws(newJWT); //BETTER
        Jwts.parserBuilder().setSigningKey(secretKeyEncoded).build().parseClaimsJws(newJWT); // FIXED
        Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(newJWT); // THIS ONE WORKS !!!!
        
        System.out.println ("done");
    }
    

    但是请注意,使用任意 Java String 的字节作为加密密钥是一个坏主意(因此我的评论)。它限制了熵,使您的系统不那么安全,特别是如果与根本不安全的具有人类意义的内容(例如我的示例!)一起使用,而且getBytes() 是依赖于语言环境的,因此如果跨区域使用它可能会导致一切失败多个系统或环境——尽管后一个问题对于 HMAC 签名可能不太重要,因为它们通常只能在单个系统上安全使用。

    这里根本没有解密(或加密),只有签名生成和验证。

    【讨论】:

      猜你喜欢
      • 2017-12-02
      • 1970-01-01
      • 2020-08-11
      • 2021-07-26
      • 1970-01-01
      • 2011-01-11
      • 1970-01-01
      • 2021-04-10
      • 2017-10-15
      相关资源
      最近更新 更多