Preamble: This might be a giant noob mistake, all the developers on my team are a little fuzzy at the Java 101 here so if we're worrying about nothing please let me know. [worried about String literals cached in permgen to be specific]
We have a simple login page that basically looks like:
//Backing Bean "LoginBean"
String username;
String password;
//getter/setter pairs
//JSF
<h:form id="login">
<h:inputText value="#{loginBean.username} />
<h:inputSecret value="#{loginBean.password} />
<h:commandButton actionListener="#{loginBean.login} />
</h:form>
My concern here is that a string literal being passed could be cached and opens potential security holes. Is there a ways to set this up so that we bypass a string literal entirely? If this were a Swing application I'd be using JPasswordField which explicitly has "char[] getPassword();"
or in code I want:
String username;
char[] password;
Thanks for the help, if it is a double post feel free to slap me, I can't seem to find it but it seems like a core issue.
My concern here is that a string literal being passed could be cached and opens potential security holes.
Your concern is only partially valid. A String literal is one that is actually present as a literal in a Java class file. A password provided by a user is not a String literal; instead it is a String object, and it will not be placed in the permanent generation unless you invoke String.intern()
.
Now assuming that you are not committing the folly of invoking String.intern()
, your other concern of having passwords around in memory ought to be addressed. This is already next to impossible in Java (due to the copying of objects performed by garbage collectors), and the JSF lifecycle makes it impossible (by requiring the construction of String objects for input values). The following bit of code was written by me to allow for managed beans to store passwords as character arrays by converting Strings to char[] arrays (and vice versa), but it is useful only for the sake of compliance checks if you've realized that the String
objects could lie around for sometime in memory:
@FacesConverter("Char[]Converter")
public class CharArrayConverter implements Converter
{
@Override
public Object getAsObject(FacesContext context, UIComponent component, String newValue)
{
if(newValue == null)
{
return newValue;
}
return newValue.toCharArray();
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
if(value == null)
{
return null;
}
char[] inputValue;
try
{
inputValue = (char[]) value;
}
catch(ClassCastException ccex)
{
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Object was not present in the desired format", null);
throw new ConverterException(message);
}
return new String(inputValue);
}
}
The converter is used in the Facelet as:
...
<p>
<h:outputLabel for="password" value="#{msg['Signup.password.label']}" />
<h:inputSecret id="password" value="#{userManager.signupRequest.password}" converter="Char[]Converter" />
</p>
...