Secure storage of credentials
import javax.servlet.*;
import javax.servlet.http.*;
public class LoginServlet extends HttpServlet {
private static final String USERNAME = "admin";
private static final String PASSWORD = "password123";
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if (USERNAME.equals(username) && PASSWORD.equals(password)) {
// Authentication successful
request.getSession().setAttribute("user", username);
response.sendRedirect("/home");
} else {
// Authentication failed
response.sendRedirect("/login");
}
}
}
In the above code, we have a
LoginServlet
class which extends
HttpServlet
. This servlet handles the login process of an application. The servlet takes a username and password from the HTTP request parameters and checks if it matches the predefined
USERNAME
and
PASSWORD
values.
The vulnerability lies in the fact that the credentials used for authentication (
USERNAME
and
PASSWORD
) are hardcoded into the application's source code in plain text. This is a serious security issue as anyone who has access to the source code can see these credentials.
If an attacker can gain access to the source code, they can directly read these credentials and use them to gain unauthorized access to the system. This could lead to unauthorized data access, data manipulation, or even more serious impacts depending on the privileges associated with these credentials.
Furthermore, since these credentials are hardcoded, they cannot be changed without changing the source code and redeploying the application. This makes it impossible to rotate these credentials on a regular basis, a common practice to mitigate the risk of credential compromise.
import javax.servlet.*;
import javax.servlet.http.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
import java.math.BigInteger;
public class LoginServlet extends HttpServlet {
private static final String USERNAME = "admin";
private static final String PASSWORD = hashPassword("password123");
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if (USERNAME.equals(username) && PASSWORD.equals(hashPassword(password))) {
// Authentication successful
request.getSession().setAttribute("user", username);
response.sendRedirect("/home");
} else {
// Authentication failed
response.sendRedirect("/login");
}
}
private static String hashPassword(String password) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(password.getBytes(StandardCharsets.UTF_8));
BigInteger number = new BigInteger(1, hash);
StringBuilder hexString = new StringBuilder(number.toString(16));
while (hexString.length() < 32) {
hexString.insert(0, '0');
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
The updated code now includes a password hashing mechanism. The password is no longer stored in plain text in the source code. Instead, the SHA-256 hashing algorithm is used to create a hashed version of the password. This hashed password is then stored and used for comparison during the authentication process.
The
hashPassword
method is a helper method that takes a password string as input and returns the hashed version of the password. It uses the
MessageDigest
class from the
java.security
package to create a
MessageDigest
instance for the SHA-256 algorithm. The password string is then converted to bytes and passed to the
digest
method of the
MessageDigest
instance to compute the hash. The resulting byte array is then converted to a
BigInteger
and then to a hexadecimal string.
During the authentication process, the entered password is hashed using the same
hashPassword
method and compared with the stored hashed password. If the hashed passwords match, the authentication is successful.
This approach ensures that even if an attacker gains access to the source code, they will not be able to retrieve the original password from the hashed password. This significantly improves the security of the application.