views:

690

answers:

6

Our web-based applications has user accounts tied down to users with the passwords specified during account creation. In the case of Java, how does one process the password securely, before persisting its hash in the database.

To be more specific, how does one ensure that the string holding the password is garbage collected within a sufficiently short interval of time ?

+2  A: 

If you create the hash on the client side, there should be no need to think about this problem. The plain password is never submitted to the server.

Mork0075
Yes, that's a good approach, but then wouldn't that also leave attackers with the ability to study the hash algorithm in use ? Granted that it is security through obscurity in a way, but it does limit the amount of information available to the attacker on how passwords are stored.
Vineet Reynolds
That would be an option but couldn't an attacker intercept the client-generated hash, too and then just generate the same HTTP request again to login?
Markus Lux
@Markus, HTTPS is always used, so the probability of a MITM attack is low or nill.
Vineet Reynolds
Why bothering with client-side encryption when HTTPS is used anyway?
Markus Lux
A: 

Two words: Local Scope. The declared variables for password processing need to have the absolute smallest scope possible.

Once the variables go out of scope, the objects are eligible for garbage collection.

Often, you're picking things out of a request. You want a very, very small transaction that accepts the request, hashes the password, persists it and redirects. The page to which you redirect can then fetch content and do all the "other" processing that is part of your application.

S.Lott
+1  A: 

There is no way to guarantee that clear text passwords are removed from memory in Java.

However a hacker doesn't need access to the memory of a program to get clear text passwords. There are much simpler ways (such as sniffing the packets) so it is highly unlikely anyone would rely on this approach.

The best approach is to have the client encrypt the password as @Mork0075 suggests. However, while it means you cannot easily get the password, a program can still get the encrypted version of passwords and so pretend to be a user. A way around this is to encrypt the whole connection using SSL.

All this is rather academic, as the simplest approach for a hacker is to monitor the packets to the database and get the password for your database. I suspect direct access to your database is more concerning... or perhaps its isn't. ;)

Peter Lawrey
I'm looking at protecting the passwords, not because an attacker would attempt this approach - the box has been compromised if he's able to peek into memory, so there are bigger things to worry about. I'm seeking to prevent passwords from appearing in a Java heap dump obtained for diagnosis.
Vineet Reynolds
+3  A: 

If you have the possibility (may be difficult in web applications), it would be better to store passwords in character arrays than to store them in strings. If you finished storing the password you can overwrite it in memory by using Array.fill() and make the reference available for the garbage collector by discarding it:

Arrays.fill(password, ' ');
password = null;

I just noticed that nulling the password would be a bit paranoid but you can do if it reassures you :)

Markus Lux
If this is possible in a web app - read the password from the servlet input stream into a byte array, and then fill the array with zeroes after persisting the password, then it should turn out to be a viable approach. The OWASP Java project uses this in an example, but not for persisting passwords.
Vineet Reynolds
Doesn't this require that the garbage collector doesn't compact the stack and thus leave a copy of the array elsewhere in memory?
KeeperOfTheSoul
@KeeperOfTheSoul: Yes, eventually it depends on GC behavior. It also depends on whether the array will be serialized or not. All in all, I wished that Java had a SecureString class similar to the one in Microsoft .Net.
Vineet Reynolds
A: 

Use a password challenge:

  1. Server chooses a challenge value and sends it to the Client
  2. Server performs a 1-way translation with the password and the challenge, ex. MD5(CONCAT(challenge, password)) and assigns it to the session.
  3. Plain-text password is now out-of-scope and ready for garbage collection.
  4. Client also performs the same translation and sends the result to the Server.
  5. If Server and Client choose the same final value, the client is authenticated.

This method prevents replay attacks, but requires the challenge value to be very unpredictable (random) and not often reused (long).

The plain-text password is only in scope during the handling of the initial connection request - not during authentication. It doesn't matter how long the 1-way translation result is in scope (not garbage collected) because it has little replay value.

Andy
That would work fine for the login process but the author asked for registering an account, so you have to store an hash value in a database, too. This hash can't be generated through a challenge value since it couldn't be restored at login.
Markus Lux
+2  A: 

You do not use a String. You use a char[] and then overwrite the char[] when done.

There are absolutely no guarantees when it comes to garbage collection (aside from that the finalizer will run before the object is collected). The GC may never run, if it runs it may never GC the String that has the password in it.

TofuBeer