(Disclaimer, this isn’t intended to be a detailed discussion on security, many of the concepts have been GREATLY simplified to hopefully help those of us less comfortable with the finer details of security/cryptography.)
As I queued up to write a this post about how difficult it is to have a unique salt for each password in a Spring 3.1 application, I’ve found it’s not difficult at all. In fact, the simplest configuration covers that exact use case, however it was a bit difficult to confirm and fully understand from the docs and information online. There are numerous references online to having to create a custom UserDetails implementation or a custom service, however none of this is required. If you’re asking yourself what’s a salt? Why do I need one? Read this article by Daniel Fernandez, it’s incredibly insightful and understandable for novices.
In practice, random (or at least variable) salt is a much better idea because, although its being random will force us to store it unencrypted along with the digest (so that we can recover it) and this will make it trivial for an attacker to know it, it will still let each of our users’ passwords remain decoupled from the rest, so that they will have to be attacked separately.
The idea here is that we want to add some additional data to be combined with each user’s password so if the password database is compromised the bad guys will have to individually crack every password and can’t get a leg up on the rest by cracking one.
In my appContext.xml configuration I’ve added a bean referencing the StandardPasswordEncoder class provided by the Spring Crypto module and reference the encoder in the password-encoder element for my authentication-provider.
<password-encoder ref=”encoder” />
<jdbc-user-service …content omitted… />
To test, I wrote a simple Class that would generate an encrypted password.
StandardPasswordEncoder encoder = new StandardPasswordEncoder();
String ep = encoder.encode(s);
Output (ran 3 times)
- Clear—> myPassword Encrytped—> d719ebc22c5d10fb0f9860fe4ac658dbc27e766a5e130cfeac919a42a718c3096b64fc524219ea54
- Clear—> myPassword Encrypted—> 4de907f676cafdca3e7d483e1dbc490bb1a837fd0baa6986cc103576258b9d26e09f4b613092263a
- Clear—> myPassword Encrypted—> 34f12d4fbeb067413cf1c29c1020fd5e2a57ddeccadedf21a79db82c442ee6db1ce18c69ca4358fa
- The user enters their username and password
- The encrypted password for that username is retrieved from the database
- The salt used to encrypt the password (the first 8 bytes) is retrieved from the encrypted value.
- The plaintext password the user entered, along with the salt retrieved from the encrypted password is encrypted using the same routine (SHA-256, 1024 iterations) as the original password.
- A check is done to see if the encrypted version of the cleartext password the user entered (with the stored salt) matches the encrypted value in the database.
The md5crypt password scrambler was created in 1995 by yours truly and was, back then, a sufficiently strong protection for passwords.
New research has shown that it can be run at a rate close to 1 million checks per second on COTS GPU hardware, which means that it is as prone to brute-force attacks as the DES based UNIX crypt was back in 1995: Any 8 character password can be found in a couple of days.
As the author of md5crypt, I implore everybody to migrate to a stronger password scrambler without undue delay.