Juan Antonio Farré Basurte (Migrated from SEC-1706) said:
It's a good practice, whenever unencrypted passwords are manipulated, to explicitly delete (overwrite) them before discarding the object. Having String passwords disallows this, as Strings are unmodifiable. Hence, whenever you use a String clear-text password, it stays around in JVM memory until garbage collector releases its space. Even then, the memory is returned to the system without overwriting it (thus containing the clear-text password). This is specially important in cloud environments where applications from different providers could be running in the same JVM. I know it's not a major security issue, but it would be nice if, wherever we have to use clear-text passwords, we could use char[]. There could be a credentials container implementation more or less like follows:
public interface CharArrayCredentialsContainer extends CredentialsContainer { char[] getCredentials(); }
public class Credentials implements CharArrayCredentialsContainer, Cloneable { private transient final CharSequence credentials;
public char[] getCredentials(){ return credentials; }
public void eraseCredentials(){ Arrays.fill(credentials,0); }
protected void finalize(){ eraseCredentials(); }
public Credentials clone(){ final Credentials c; try{ c=(Credentials) super.clone(); }catch(CloneNotSupportedException e){ throw new AssertionError(e); } c.credentials=Arrays.copyOf(credentials, credentials.length); return c; } }
PasswordEncoder should overload both its methods to allow char[] for, at least, rawPass.
The problem of all this is in UsernamePasswordAuthenticationFilter. It uses HttpServletRequest.getParameter() to get the password, and it returns a String. One option is not to use getParameter-related methods at all and directly parse the request body with getReader. But may be this would interfere with other filters/servlets/controllers that might be using getParameter. If not possible at all, at least I'd change (or override) UsernamePasswordAuthenticationFilter.obtainPassword(request) to this:
return new Credentials(request.getParameter(passwordParameter));
Obviously with a constructor in Credentials taking a String.
An finally (I think), security providers should know how to deal with CharArrayCredentialsContainer instances, and check for this interface before defaulting to current behaviour.
I find no easier way to implement all this and I find nothing in the forum. If anybody knows a more straightforward way of achieving this functionality, I'll be grateful to know :)
Thanks,
Juan
Comment From: spring-projects-issues
Juan Antonio Farré Basurte said:
A small detail. There could be a CharSequence wrapper of char[]. Then getCredentials would return CharSequence. PasswordEncoder could then just use CharSequences (which is anyway a nice improvement). And there would be no direct public access to the wrapped char[], so nobody can modify it, except erasing it, and there would be no need for it to be Cloneable. Credentials could also override equals to compare the char[].
Comment From: rwinch
I'm closing this as will not fix. Spring Security operates in environments like servlet containers, webflux, etc. The problem is the underlying container still has a reference to the password as a String, so it would have to be implemented by passing the char[] of a String obtained from the HTTP request which would not be garbage collected. Without support from things like the Servlet container, this feature just adds unnecessary overhead.