Business information leak - JWT - Java

Business information leak - JWT - Java

Need

Protection of sensitive business information in JWTs

Context

  • Usage of Java 8 for developing applications with enhanced features and performance improvements
  • Usage of javax.servlet-api for building Java web applications with Servlets
  • Usage of io.jsonwebtoken for JWT (JSON Web Token) authentication and authorization

Description

Non compliant code

        import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

public class VulnerableServlet extends HttpServlet {
    private static final String SECRET_KEY = "SECRET_KEY";

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        String jwt = Jwts.builder()
                .setSubject(username)
                .claim("password", password)
                .signWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()), SignatureAlgorithm.HS256)
                .compact();

        resp.setHeader("Authorization", "Bearer " + jwt);
    }
}
        
        

The above Java code is a representation of a servlet which is vulnerable to business information leak through JWT (JSON Web Token).

In the doPost method, the servlet takes a username and password from the request parameters. These are then used to create a JWT which is signed with a secret key and the HS256 algorithm. The generated JWT is then set in the Authorization header of the response.

The vulnerability lies in the fact that the password, which is sensitive business information, is included in the JWT. This is a problem because JWTs are not encrypted but only encoded. This means that anyone who intercepts the JWT can easily decode it and see the password in plain text. This can lead to unauthorized access to the system and potential data breaches.

Steps

  • Do not include sensitive information such as username and password in the JWT payload.
  • Instead, use the JWT to store a unique identifier or token that can be used to retrieve the necessary information securely.
  • Implement a separate authentication mechanism to verify the username and password provided by the user.
  • Store the sensitive information securely in a database or other secure storage.
  • When generating the JWT, only include the necessary information such as the user identifier or token.
  • Use a strong and secure secret key for signing the JWT to prevent unauthorized access.
  • Ensure that the secret key is securely stored and not exposed in the code or configuration files.
  • Regularly review and update the JWT implementation to incorporate any security patches or best practices.

Compliant code

        import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

public class SecureServlet extends HttpServlet {
    private static final String SECRET_KEY = "SECRET_KEY";

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        // Implement your authentication mechanism here to verify the username and password

        // If authentication is successful, generate a unique user identifier or token
        String userIdentifier = generateUserIdentifier(username, password);

        String jwt = Jwts.builder()
                .setSubject(userIdentifier)
                .signWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()), SignatureAlgorithm.HS256)
                .compact();

        resp.setHeader("Authorization", "Bearer " + jwt);
    }

    private String generateUserIdentifier(String username, String password) {
        // Implement your method to generate a unique user identifier or token
        return "";
    }
}
        
        

The updated code no longer includes sensitive information such as the username and password in the JWT payload. Instead, it uses the JWT to store a unique user identifier or token that can be used to retrieve the necessary information securely.

The doPost method first retrieves the username and password from the request parameters. It then calls a separate authentication mechanism (not shown in this code) to verify the provided username and password.

If the authentication is successful, the method generates a unique user identifier or token by calling the generateUserIdentifier method. This identifier is then included in the JWT payload.

The JWT is signed using a secret key and the HMAC-SHA256 algorithm. The secret key is stored as a constant in the code, but in a real-world application, it should be securely stored in a separate configuration file or secure storage.

Finally, the JWT is added to the Authorization header of the response. This JWT can then be used by the client to authenticate subsequent requests.

References