Problem

You want to store passwords securely to prevent anybody—even yourself and other technical staff—from being able to view them.

Solution

In this recipe we're going to use Spring Security 2 to store passwords securely. We'll also show how to authenticate against secured passwords.

Spring Security makes it fairly easy to store passwords securely. The actual storage mechanism (database, LDAP or other) doesn't really matter since that's abstracted away, which is nice.

Before we jump into the how-to part of the recipe, let's briefly examine hash functions and how they work, since we'll need this background to understand what we're doing in the subsequent discussion.

Understanding hash functions

The idea behind this recipe is that we want to store passwords in encrypted form in the persistent store. There are in general two different approaches to encryption here: ciphers and hash functions. The two are similar in that each provides a way to encrypt data, but they differ in that only ciphers provide an easy way (assuming you know a secret key) to decrypt the data. Hash functions don't provide for easy decryption; hence they are sometimes referred to as one-way hash functions. All hash functions, however, are one-way.

When storing encrypted passwords, the typical practice is to use a hash function, such as MD5 or SHA-1, to encrypt the password before saving it. The reason for preferring a hash function to a cipher is that we don't usually want anybody to be able to recover the password: we never (or should never) display it on the screen or in e-mails, for example. A string of plaintext encrypted by a hash function is called a hash.

Here are a couple of examples of hashed text:

The first string is an SHA-1 hash of the string dardy, and the second is an MD5 hash of the string friend. You can easily Google for free online hash calculators, both for MD5 and for SHA-1.

You might ask how we can use stored password hashes to authenticate users if we can't recover the plaintext password from the hash. The answer is that we don't compare plaintext passwords, but rather we compare the hashes. When the user submits a username/password pair, we hash the submitted password and compare that hash with the stored hash. If the two match, then we conclude that the submitted password was correct.

We can draw this conclusion due to a special property of hash functions: in general, different plaintext inputs map to different hashes. That is, in general, different plaintext inputs very, very rarely "collide." There are of course limits to this non-collision, but for practical purposes we can assume that different passwords will have different hashes. So if the hashes match, then the submitted password was correct.

Sound good? Let's start with the authentication side of things, and then we'll tackle user registrations.