Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

notes for security/jwt/JwtUtils.java #1

Open
MilkSF opened this issue May 12, 2022 · 1 comment
Open

notes for security/jwt/JwtUtils.java #1

MilkSF opened this issue May 12, 2022 · 1 comment

Comments

@MilkSF
Copy link

MilkSF commented May 12, 2022

This issue record the problems in programming, and the solutions that I used.

In security/jwt/JwtUtils.java
.signWith(SignatureAlgorithm.HS512, jwtSecret) will use JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey) throws InvalidKeyException; method.
This method will use base64 decoder to decode base64EncodedSecretKey, so the length of jwtSecret in application.properties could not be too short, if the length of secret string is not enough, the program may throw the following exception:

io.jsonwebtoken.security.WeakKeyException: The signing key's size is xxx bits which is not secure enough for the HS512 algorithm.  
The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HS512 MUST have a size >= 512 bits (the key size must be greater than or equal to the hash output size).  
Consider using the io.jsonwebtoken.security.Keys class's 'secretKeyFor(SignatureAlgorithm.HS512)' method to create a key guaranteed to be secure enough for HS512.  
See https://tools.ietf

To solve this exception, I should provide long enough secret string, futher more, I'd like to use origin secret string instead of Base64 encoded string, so I use JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKey) throws InvalidKeyException; method, and the code in JwtUtils.java like this:

        return Jwts.builder()
                .setSubject((userPrincipal.getUsername()))
                .setIssuedAt(new Date())
                .setExpiration(new Date((new Date().getTime() + jwtExpirationMs)))
                .signWith(SignatureAlgorithm.HS512, jwtSecret.getBytes(StandardCharsets.UTF_8))
                .compact();

and in application.properties file, jwtSecret contains at least 64 chars.


I noticed that signWith(SignatureAlgorithm alg, byte[] secretKey), signWith(SignatureAlgorithm alg, String base64EncodedSecretKey) and Jwts.parser() are deprecated in jjwt 0.11.5, so I use new methods, the code in JwtUtils.java like this:

@Component
public class JwtUtils {
    private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);

    @Value("${indicatorManagement.app.jwtSecret}")
    private String jwtSecret;
    @Value("${indicatorManagement.app.jwtExpirationMs}")
    private int jwtExpirationMs;
    public String generateJwtToken(Authentication authentication) {
        UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
        return Jwts.builder()
                .setSubject((userPrincipal.getUsername()))
                .setIssuedAt(new Date())
                .setExpiration(new Date((new Date().getTime() + jwtExpirationMs)))
                // .signWith(SignatureAlgorithm.HS512, jwtSecret.getBytes(StandardCharsets.UTF_8))
                .signWith(Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8)), SignatureAlgorithm.HS512)
                .compact();
    }

    public String getUserNameFromJwtToken(String token) {
        // return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
        return Jwts.parserBuilder()
                .setSigningKey(jwtSecret.getBytes(StandardCharsets.UTF_8))
                .build().parseClaimsJws(token).getBody().getSubject();
    }

    public boolean validateJwtToken(String authToken) {
        try {
            // Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
            Jwts.parserBuilder().setSigningKey(jwtSecret.getBytes(StandardCharsets.UTF_8))
                    .build().parseClaimsJws(authToken);
            return true;
        } catch (SignatureException e) {
            logger.error("Invalid JWT signature: {}", e.getMessage());
        } catch (MalformedJwtException e) {
            logger.error("Invalid JWT token: {}", e.getMessage());
        } catch (ExpiredJwtException e) {
            logger.error("JWT token is expired: {}", e.getMessage());
        } catch (UnsupportedJwtException e) {
            logger.error("JWT token is unsupported: {}", e.getMessage());
        } catch (IllegalArgumentException e) {
            logger.error("JWT claims string is empty: {}", e.getMessage());
        }
        return false;
    }
}

Technology

Java 11.0.15
Spring Boot 2.6.7 (with Spring Security, Spring Data MongoDB)
jjwt 0.11.5
MongoDB 4.4.12
Maven 3.8.1

PS: Thanks to the author for the great spring boot examples.

@patricksilva1
Copy link

@MilkSF Thanks, I was looking for this too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants