4

TLDR; Is parsing a char array through the String class in the form of String.valueOf(charArray); more safe than making an object of the String class? I am trying to understand/extend the discussion that is had in: Why is char[] preferred over String for passwords?

I have just recently read up a lot about how to handle passwords "securely" ish in Java, but there is still one issue I do not quite know how to solve. When you take in a password from a jPasswordField it comes as an array of chars. This is great and all because you can more easily overwrite the array with zeroes than having to wait for the garbage collector to come sweep up things like strings and whatnot.

My issue lies in the following: When I want to run an update statement in SQL to update a password, I simply CAN NOT put in the array of chars, because it is the wrong format. When I do something like Arrays.toString(arrayName); I get it with format:

[e, a, c, h, o, f, t, h, e, l, e, t, t, e, r, s]

The only way I can put it into a database column with... let's say VARCHAR(100) without all of the commas and the spaces seems to be to write something like:

String stringPassword="";
int i=0;
for(char a:newPassword){
    stringPassword=stringPassword+newPassword[i];
    i++;
}

If I do something like this though, have I not just destroyed the whole point of using the array of chars? Googling around hasn't really helped me solve this one.

Thanks in advance for your time.

EDIT 1: Thanks KKaar for the possible solution:

char[] passwordArray;
String.valueOf(passwordArray);

This works just fine syntax-wise for the purposes I need it for, but I still don't know if it is safe. It doesn't make a variable out of it if I make the String.valueOf(passwordArray) in the preparedStatement syntax, but it still parses the values through the String class. Does that mean it is still in danger, or is it safe-ish?

Staggen
  • 73
  • 7
  • `String.valueOf(arrayName)` should work in your case – KKaar May 23 '18 at 20:29
  • @KKaar and doing that doesn't really make it a string since I don't make a variable out of it, and therefore I can still avoid all of the security issues that come with strings? – Staggen May 23 '18 at 20:33
  • @Staggen I don't really get what do you mean. You can easily assign it to a variable if you want to, or just pass it as `String.valueOf(...)` to the database query. Internally `String.valueOf(...)` uses the exact same approach as Sid pointed out in the last comment (just creating a `new String`. This approach is just way better looking than the for loop approach :) – KKaar May 23 '18 at 20:42
  • 2
    @KKaar OP is probably meant reasons described in: [Why is char array preferred over String for passwords?](https://stackoverflow.com/q/8881291) – Pshemo May 23 '18 at 20:48
  • 2
    @GriffeyDog Oh. I totally misunderstood the question. Sorry. Had no idea that holding password as a String in memory for a while would actually expose security threats. Thanks for pointing it out. – KKaar May 23 '18 at 20:53
  • I don't know if there is a difference between making a variable out of it and not making a variable out of it. Like, memory wise I mean. I know that String password="Password123" is a security threat, but is String.valueOf(passwordArray) of a char array a security threat in the same way? I mean, you don't assign it to a variable, but you still parse it through the String class. – Staggen May 23 '18 at 21:01
  • Basically `String.valueOf(char[])` still creates `String` object in memory which is very secure. – Ivan May 23 '18 at 21:11
  • 2
    i think you should store hash password instead of password itself – CSK May 23 '18 at 21:13
  • 1
    If someone in your system is able to look into the memory of the active process and view the password from String, it should be your least concern - the system has already been broken, so what's the difference ? I would not care about it and I would store the password in String instead of in char [] – krokodilko May 23 '18 at 21:34

1 Answers1

3

String.valueOf(charArray) creates a String and is just as unsafe.

Nowadays one can use JDBC:

char[] password = ...;
try (PreparedStatement stmt = con.prepareStatement("...")) {
    Reader reader = new CharArrayReader(password);
    stmt.setCharacterStream(1, reader);
    stmt.executeUpdate();
    stmt.clearParameters();
}
Arrays.fill(password, ' ');

This ensures that after this code is executed no object floats around to be garbage collected, that may show the password.

Of course only, if the JDBC driver does not leak. The clearParameters seems a bit overdone, but who knows.

CharArrayReader does not copy the passed array, hence this is safe too.


Asked for the concrete code:

String sql = "UPDATE teachers SET password=? WHERE firstname=? AND lastname=?";
try (PreparedStatement pStat = con.prepareStatement(sql)) {
    Reader reader = new CharArrayReader(newPassword);
    pStat.setCharacterStream(1, reader);
    pStat.setString(2, firstName);
    pStat.setString(3, lastName);
    pStat.executeUpdate();
    pStat.clearParameters();
}
Arrays.fill(newPassword, ' ');

As the statement should be closed, I took the liberty to use a local variable.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • How do I apply that solution for my prepared statement below? `PreparedStatement pStat=con.prepareStatement("UPDATE teachers SET password='"+String.valueOf(newPassword)+"' WHERE firstname='"+firstName+"' AND lastname='"+lastName+"';");` – Staggen May 23 '18 at 23:05