JWT 无法从密钥中破译
Posted
技术标签:
【中文标题】JWT 无法从密钥中破译【英文标题】:JWT can not be decipher from keys 【发布时间】: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 !!!!
【问题讨论】:
【参考方案1】:signWith
overload that takes a String
要求字符串包含实际密钥的 base64 编码,但其他重载(包括 Key
和 byte[]
)采用实际密钥而不是 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 签名可能不太重要,因为它们通常只能在单个系统上安全使用。
这里根本没有解密(或加密),只有签名生成和验证。
【讨论】:
以上是关于JWT 无法从密钥中破译的主要内容,如果未能解决你的问题,请参考以下文章
错误,Lcobucci\JWT\Signer\InvalidKeyProvided:无法解析您的密钥