I have a Spring Boot application that uses a CredentialsService class to store credentials as GuardedStrings and return them when requested by other classes.
Where the problem arises is in the fact that we use Checkmarx to scan our code and catch potential issues. Where storage of the usernames/passwords are not a problem anymore, I still have to use a String variable to return the plain text credentials. Checkmarx doesn't like that - especially for passwords.
This is the abbreviated view of the CredentialsService:
@Component
public class CredentialsService {
final ExecutorService executor = Executors.newSingleThreadExecutor();
private GuardedString customerApiPassword;
. . .
private StringBuilder clearCustomerApiPassword;
public CredentialsService( . . .
@Value("${customerapi.pwd}") String customerApiPassword,. . .) {
setCustomerApiPassword(customerApiPassword);
. . .
}
private void setCustomerApiPassword(String customerApiPasswordString) {
this.customerApiPassword = new GuardedString(customerApiPasswordString.toCharArray());
this.customerApiPassword.makeReadOnly();
}
public String getCustomerApiPasswordNo() {
clearCustomerApiPassword = new StringBuilder();
customerApiPassword.access(new GuardedString.Accessor() {
@Override
public void access(final char[] clearChars) {
clearCustomerApiPassword.append(clearChars);
}
});
customerApiPassword.dispose();
System.out.println("DGC: clearCustomerApiPassword is " + clearCustomerApiPassword);
Runnable clearFromMemory = () -> {
clearCustomerApiPassword = null;
System.out.println("DGC: clearCustomerApiPassword is " + clearCustomerApiPassword);
};
executor.execute(clearFromMemory);
return clearCustomerApiPassword.toString();
}
And then a requester accesses the values it needs with:
IntegrationApiUtil.setBasicAuthKey(headers, credentialsService.getCustomerApiUsername(), credentialsService.getCustomerApiPassword());
However Checkmarx is still not happy. I use the same approach for storing the GuardedString usernames and passwords and the exact same approach to clearing the Strings that are returned. Checkmarx is fine with the usernames, but it still complains about the passwords:
Method clearCustomerApiPassword; at line 24 of
src/main/java/com/.../service/CredentialsService.java
defines clearCustomerApiPassword, which is designated to contain user passwords. However, while plaintext
passwords are later assigned to clearCustomerApiPassword, this variable is never cleared from memory.
I have tried all sorts of things - a finalize method to destroy the service after it is last used, a disposeAll method to explicitly set all variables to null and call the garbage collector. With the code above I am creating a separate thread in each get method to set the 'clear' variables to null as I return the value to the requester. While I can confirm that this latest approach does provide the requester with the correct values and also sets the variables to null, nothing seems to satisfy Checkmarx.
Does anyone have any ideas?
Thanks in advance.
D