fix(security): 修复 JWT 算法降级绕过并加固令牌校验

补充 alg 白名单校验(仅允许 HS256),parseToken 与 invalidateToken 增加签名校验
This commit is contained in:
Ray.Hao
2026-09-30 16:08:41 +08:00
parent 9deaa2568a
commit c08b565b2f

View File

@@ -39,6 +39,9 @@ import java.util.stream.Collectors;
@Service
public class JwtTokenManager implements TokenManager {
// 允许的签名算法,防止 alg:none 等算法降级攻击
private static final String ALLOWED_ALGORITHM = "HS256";
private final SecurityProperties securityProperties;
private final RedisTemplate<String, Object> redisTemplate;
private final byte[] secretKey;
@@ -68,6 +71,9 @@ public class JwtTokenManager implements TokenManager {
@Override
public Authentication parseToken(String token) {
JWT jwt = JWTUtil.parseToken(token);
if (!isAlgorithmAllowed(jwt) || !jwt.setKey(secretKey).verify()) {
throw new TokenInvalidException(ResultCode.ACCESS_TOKEN_INVALID);
}
JSONObject payloads = jwt.getPayloads();
SecurityUserDetails userDetails = new SecurityUserDetails();
userDetails.setUserId(payloads.getLong(JwtClaimConstants.USER_ID));
@@ -118,6 +124,9 @@ public class JwtTokenManager implements TokenManager {
private boolean validateToken(String token, boolean validateRefreshToken) {
JWT jwt = JWTUtil.parseToken(token);
if (!isAlgorithmAllowed(jwt)) {
return false;
}
boolean isValid = jwt.setKey(secretKey).validate(0);
if (isValid) {
@@ -162,6 +171,9 @@ public class JwtTokenManager implements TokenManager {
token = token.substring(SecurityConstants.BEARER_TOKEN_PREFIX.length());
}
JWT jwt = JWTUtil.parseToken(token);
if (!isAlgorithmAllowed(jwt) || !jwt.setKey(secretKey).verify()) {
return;
}
JSONObject payloads = jwt.getPayloads();
String jti = payloads.getStr(JWTPayload.JWT_ID);
Integer expirationAt = payloads.getInt(JWTPayload.EXPIRES_AT);
@@ -273,4 +285,15 @@ public class JwtTokenManager implements TokenManager {
redisTemplate.opsForValue().set(revokedJtiKey, Boolean.TRUE);
}
}
/**
* 校验 JWT 头部算法是否在允许的白名单中,防止 alg:none 等算法降级攻击
*
* @param jwt JWT 对象
* @return 是否允许
*/
private boolean isAlgorithmAllowed(JWT jwt) {
Object algorithm = jwt.getHeader("alg");
return algorithm != null && ALLOWED_ALGORITHM.equals(algorithm.toString());
}
}