mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-12-06 17:18:54 +08:00
修复verify方法在定义alg为none时验证失效问题(issue#4105@Github)
This commit is contained in:
parent
97e56c48eb
commit
dcdba8314d
@ -1,12 +1,13 @@
|
|||||||
|
|
||||||
# 🚀Changelog
|
# 🚀Changelog
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
# 5.8.42(2025-10-18)
|
# 5.8.42(2025-10-22)
|
||||||
|
|
||||||
### 🐣新特性
|
### 🐣新特性
|
||||||
* 【core 】 `ListUtil`增加`zip`方法(pr#4052@Github)
|
* 【core 】 `ListUtil`增加`zip`方法(pr#4052@Github)
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
|
* 【jwt 】 修复verify方法在定义alg为`none`时验证失效问题(issue#4105@Github)
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
# 5.8.41(2025-10-12)
|
# 5.8.41(2025-10-12)
|
||||||
|
|||||||
@ -410,6 +410,16 @@ public class JWT implements RegisteredPayload<JWT> {
|
|||||||
signer = NoneJWTSigner.NONE;
|
signer = NoneJWTSigner.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户定义alg为none但是签名器不是NoneJWTSigner
|
||||||
|
if(NoneJWTSigner.isNone(getAlgorithm()) && !(signer instanceof NoneJWTSigner)){
|
||||||
|
throw new JWTException("Alg is 'none' but use: {} !", signer.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
// alg非none,但签名器是NoneJWTSigner
|
||||||
|
if(signer instanceof NoneJWTSigner && !NoneJWTSigner.isNone(getAlgorithm())){
|
||||||
|
throw new JWTException("Alg is not 'none' but use NoneJWTSigner!");
|
||||||
|
}
|
||||||
|
|
||||||
final List<String> tokens = this.tokens;
|
final List<String> tokens = this.tokens;
|
||||||
if (CollUtil.isEmpty(tokens)) {
|
if (CollUtil.isEmpty(tokens)) {
|
||||||
throw new JWTException("No token to verify!");
|
throw new JWTException("No token to verify!");
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package cn.hutool.jwt.signers;
|
package cn.hutool.jwt.signers;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
|
||||||
import cn.hutool.core.util.ReUtil;
|
import cn.hutool.core.util.ReUtil;
|
||||||
|
import cn.hutool.jwt.JWTException;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
@ -232,10 +232,12 @@ public class JWTSignerUtil {
|
|||||||
* @return 签名器
|
* @return 签名器
|
||||||
*/
|
*/
|
||||||
public static JWTSigner createSigner(String algorithmId, byte[] key) {
|
public static JWTSigner createSigner(String algorithmId, byte[] key) {
|
||||||
Assert.notNull(key, "Signer key must be not null!");
|
if (NoneJWTSigner.isNone(algorithmId)) {
|
||||||
|
if(null == key){
|
||||||
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
|
return none();
|
||||||
return none();
|
}else{
|
||||||
|
throw new JWTException("When key is not null, algorithmId must not be none.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new HMacJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), key);
|
return new HMacJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), key);
|
||||||
}
|
}
|
||||||
@ -248,10 +250,12 @@ public class JWTSignerUtil {
|
|||||||
* @return 签名器
|
* @return 签名器
|
||||||
*/
|
*/
|
||||||
public static JWTSigner createSigner(String algorithmId, KeyPair keyPair) {
|
public static JWTSigner createSigner(String algorithmId, KeyPair keyPair) {
|
||||||
Assert.notNull(keyPair, "Signer key pair must be not null!");
|
if (NoneJWTSigner.isNone(algorithmId)) {
|
||||||
|
if(null == keyPair){
|
||||||
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
|
return none();
|
||||||
return none();
|
}else{
|
||||||
|
throw new JWTException("When key is not null, algorithmId must not be none.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// issue3205@Github
|
// issue3205@Github
|
||||||
@ -270,11 +274,14 @@ public class JWTSignerUtil {
|
|||||||
* @return 签名器
|
* @return 签名器
|
||||||
*/
|
*/
|
||||||
public static JWTSigner createSigner(String algorithmId, Key key) {
|
public static JWTSigner createSigner(String algorithmId, Key key) {
|
||||||
Assert.notNull(key, "Signer key must be not null!");
|
if (NoneJWTSigner.isNone(algorithmId)) {
|
||||||
|
if(null == key){
|
||||||
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
|
return none();
|
||||||
return NoneJWTSigner.NONE;
|
}else{
|
||||||
|
throw new JWTException("When key is not null, algorithmId must not be none.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key instanceof PrivateKey || key instanceof PublicKey) {
|
if (key instanceof PrivateKey || key instanceof PublicKey) {
|
||||||
// issue3205@Github
|
// issue3205@Github
|
||||||
if(ReUtil.isMatch("ES\\d{3}", algorithmId)){
|
if(ReUtil.isMatch("ES\\d{3}", algorithmId)){
|
||||||
|
|||||||
@ -10,10 +10,27 @@ import cn.hutool.core.util.StrUtil;
|
|||||||
*/
|
*/
|
||||||
public class NoneJWTSigner implements JWTSigner {
|
public class NoneJWTSigner implements JWTSigner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义一个常量ID_NONE,表示没有ID的情况
|
||||||
|
*/
|
||||||
public static final String ID_NONE = "none";
|
public static final String ID_NONE = "none";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个NoneJWTSigner实例,用于处理没有签名的JWT
|
||||||
|
*/
|
||||||
public static NoneJWTSigner NONE = new NoneJWTSigner();
|
public static NoneJWTSigner NONE = new NoneJWTSigner();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的算法是否为无签名的算法
|
||||||
|
*
|
||||||
|
* @param alg 算法
|
||||||
|
* @return 如果是无签名的算法,则返回true;否则返回false
|
||||||
|
* @since 5.8.42
|
||||||
|
*/
|
||||||
|
public static boolean isNone(final String alg) {
|
||||||
|
return StrUtil.isBlank( alg) || StrUtil.equalsIgnoreCase(alg, ID_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sign(String headerBase64, String payloadBase64) {
|
public String sign(String headerBase64, String payloadBase64) {
|
||||||
return StrUtil.EMPTY;
|
return StrUtil.EMPTY;
|
||||||
|
|||||||
67
hutool-jwt/src/test/java/cn/hutool/jwt/Issue4105Test.java
Normal file
67
hutool-jwt/src/test/java/cn/hutool/jwt/Issue4105Test.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package cn.hutool.jwt;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class Issue4105Test {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void verifyNoneTest() {
|
||||||
|
// {"alg": "none"}.{"exp": 1642196407}
|
||||||
|
// 当定义alg为none时,校验总是成功
|
||||||
|
String head = Base64.encode("{\"alg\": \"none\"}");
|
||||||
|
String payload = Base64.encode("{\"exp\": 1642196407}");
|
||||||
|
String token = StrUtil.format("{}.{}.", head, payload);
|
||||||
|
|
||||||
|
final JWT jwt = JWTUtil.parseToken(token);
|
||||||
|
Assertions.assertNull(jwt.getSigner());
|
||||||
|
// 对于签名为none的JWT,verify()方法总是返回true
|
||||||
|
Assertions.assertTrue(jwt.verify());
|
||||||
|
|
||||||
|
// 对于签名为none的JWT,但是定义了key,不一致报错
|
||||||
|
final JWT jwt2 = JWTUtil.parseToken(token);
|
||||||
|
Assertions.assertThrows(JWTException.class, ()-> jwt2.setKey("123".getBytes(StandardCharsets.UTF_8)).verify());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void verifyEmptyTest() {
|
||||||
|
// {"alg": "none"}.{"exp": 1642196407}
|
||||||
|
// 当定义alg为none时,校验总是成功
|
||||||
|
String head = Base64.encode("{\"alg\": \"\"}");
|
||||||
|
String payload = Base64.encode("{\"exp\": 1642196407}");
|
||||||
|
String token = StrUtil.format("{}.{}.", head, payload);
|
||||||
|
|
||||||
|
final JWT jwt = JWTUtil.parseToken(token);
|
||||||
|
Assertions.assertNull(jwt.getSigner());
|
||||||
|
// 对于签名为none的JWT,verify()方法总是返回true
|
||||||
|
Assertions.assertTrue(jwt.verify());
|
||||||
|
|
||||||
|
// 对于签名为none的JWT,setKey使用的签名总是
|
||||||
|
final JWT jwt2 = JWTUtil.parseToken(token);
|
||||||
|
Assertions.assertThrows(JWTException.class, ()-> jwt2.setKey("123".getBytes(StandardCharsets.UTF_8)).verify());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void verifyHs256Test() {
|
||||||
|
// {"alg": "none"}.{"exp": 1642196407}
|
||||||
|
// 当定义alg为none时,校验总是成功
|
||||||
|
String head = Base64.encode("{\"alg\": \"HS256\"}");
|
||||||
|
String payload = Base64.encode("{\"exp\": 1642196407}");
|
||||||
|
String token = StrUtil.format("{}.{}.", head, payload);
|
||||||
|
|
||||||
|
final JWT jwt = JWTUtil.parseToken(token);
|
||||||
|
Assertions.assertNull(jwt.getSigner());
|
||||||
|
|
||||||
|
// 未定义签名器或key,但是JWT中要求了签名算法,异常
|
||||||
|
Assertions.assertThrows(JWTException.class, jwt::verify);
|
||||||
|
|
||||||
|
// 手动定义签名器,但是签名部分为空或不一致,返回false
|
||||||
|
final JWT jwt2 = JWTUtil.parseToken(token);
|
||||||
|
Assertions.assertFalse(jwt2.setKey("123".getBytes(StandardCharsets.UTF_8)).verify());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user