First8 staat voor vakmanschap. Al onze collega’s zijn een groot aanhanger van Open Source en in het bijzonder het Java-platform. Wij zijn gespecialiseerd in het pragmatisch ontwikkelen van bedrijfskritische Java toepassingen waarbij integratie van systemen, hoge eisen aan beveiliging en veel transacties een belangrijke rol spelen. Op deze pagina vind je onze blogs.

Password storage (for Ducktown Times)

This is the blogpost as promised in the First8 Friday video blog of August 2015. This post presents the idea of storing passwords as safely as possible for the purpose of authentication.

First a word of caution. User management is more work than you might think. It is also done a lot of times over and over again. Role based access? Adding and removing users and accounts? If at all possible, try to avoid the need, by either using LDAP in the enterprise, or public authentication methods like Google, Facebook or Twitter-integration for public sites.

Storing passwords

The requirements demand it, we are asked to do it, so let’s store passwords. In the video, our friend Donald Duck has created a user-table with plaintext passwords. It is surprising how often you still see sites that store passwords in this way. From a user-friendly perspective this is great: you can e-mail the passwords to the users if they have forgotten it, or look it up for them etc. Also, for developement, it’s an easy start. The examples below are based on PostgresQL. As a preparation: create an empty database to play with.

Let’s create Donalds user-table:

And add some users:

The result is this table:

We can easily see the plaintext passwords. We can also see the role every user has, in particular that Kwak is the second admin.

Improve on this: hash the passwords

We were either hacked or we wish to prevent a hack from revealing the passwords instantly. So, we apply safe-looking hashing on the passwords.

Enable the crypto algorithms in PostgresQL (if needed). This applies per database, but has to be done by the database administrator. She has to connect to the database where the extension is needed, while keeping the root role.

Introduce the new column:

Fill it with data:

Remove the plain-text column:

And inspect the result

Hashing is a one-way street: you cannot easily calculate the original from the hash, however there is a catch.
We can still see that Kwik, Kwek and Kwak have the same password. So if an attacker can swindle Kwik to get his password, she can login as Kwak and become an admin!

And there is one other problem with this solution: md5 is designed to be quick. It is designed as an algorithm to check the integrity of large files or .iso-images. Calculating the hash of a short string costs in the order of microseconds. My four year old laptop performs 10M MD5-digest operations in 2.5 seconds, when using Java on a single core. That is 0.25 microsecond per digest. Or, to be even more precise: When performing 20M digest calculations the CPU performed about 26G instructions, That is a bit over 1000 CPU instructions per digest operation.

This speed gives the attacker a few tricks: she can create a list of hashes for every likely password, and then use that as a lookup-table for md5 hashed passwords. John the Ripper uses this kind of tricks to analyse a password table for weak passwords. Attackers know that people will use numbers for letters, so they just create a few variations of every dictionary word.

BCrypt: the solution designed for this problem

In 1999, Niels Provos and David Mazières presented an elegant solution. A hash that was designed to be slow. “Salt bits” are used in initialization, which is an expensive operation and which takes a configurable amount of time. This configuration is stored with the salt and the hash in one text-string. So if over time computers get twice as fast, one can update the strength as soon as users (are forced to) update their password.

So let’s reset to the first table we had, with just the plaintext passwords.

And add a column for the bcrypted password:

Then fill that column. Note that this configuration takes quite some time to be performed.

This 12 is a relative large number, the scale is logarithmic: 10 would be four times quicker. It is 2^n rounds of a cryptographic operation to produce the initialization bits from the salt, which are finally combined with the bits from the password to form the hash.

The strings that crypt produces contain, amongst other things, the number of rounds. If new passwords are created with 13 as the configuration for the duration, we can still validate these current passwords. Validating is done with a query like this:

Conclusion

Try to avoid storing passwords and introducing user management in your application. There are other solutions for that in the enterprise and in the open internet. If you have to store authentication credentials like passwords, try to store them as safe as possible.

With the support of an Open Source (or closed) database we demonstrate that we can use a safe password storage algorithm fairly easily. BCrypt has proven its worth over the last 16 years.

Having the plain text passwords made life easy in this demonstration. In the next blogpost and video we’ll present a migration path from the md5-hashes to the bcrypt hashes, without having plain-text passwords.