2013-04-17 15:20:07

Passwords and hashes on the web.


Categories php security

Since I've been working in web development field for couple of years I've seen most of the projects that use md5 or sha* hashes to store passwords. Hashes are good because they are one way, easy and efficient to compute, very inefficient to revert and very hard to create collisions (basically discover different input for the same output).

Personally I think that it is a very bad idea and if your project has at least some degree of sensitive data you should think twice before using this approach.

Let's imagine that for some reason you have an SQL injection in you application:


This will give up all the hashes. 99% of password are small and dictionary based... and this creates a problem: 'lookup tables'. Lookup tables are tables that map 'password' <=> 'hash'. They are very CPU effective but require quite a lot of space. For instance passwords <= 6 chars (95^6 = 735.091.890.625 passwords) will require nearly half petabyte of storage in a storage efficient file-system. Still, lookup tables can be improved using a so-called 'rainbow tables' (read more here: http://kestas.kuliukas.com/RainbowTables/). Rainbow tables are slower than lookup tables but are much more space efficient. Most of the password with <= 7 chars will only require 64GB of storage and the chain length of 71.000. It will find most of the passwords very quickly.

So... what about defending ourselves? Salt you say:
hash = md5(salt + password)

Great, now what? Well salts could be global per project or even could be salt per hash which is much more secure. Just make them quite long, at least 50 chars. If due to bad planning your salt is stored in your DB, then you have a problem again. Not that big with rainbow tables because salt defeat them but still, as I've said before, hashes are easy and efficient to compute... EFFICIENT (our enemy).

Hash functions for starters were made to be FAST. For instance, create MD5 hash for 2GB file takes ~5 seconds on QuadCore @ 3GHz. Imagine now a 7 char password... So:

http://www.openwall.com/john/ -> problem
http://hashcat.net/oclhashcat-plus/ -> problem

Also keep in mind brute forcing with dictionary, combination based, fingerprint based, etc, etc, etc. Let's be a bit more specific now:

Medium/pro grade laptop with i5/i7 CPU can 33 million md5 hashes per SECOND. 20 million sha256 hashes per SECOND. This means 6 char password will crack in 5 hours, 7 char password in 22 days. Whole English dictionary in 1.8 seconds. Want some more?
50 GPU cluster: 360 Billion md5 hashes per second and costs less than 50k €.

6 char passwords will be vanished in 2 seconds, 7 in 3 minutes, 8 in 5 hours and whole English dictionary in 0.35 seconds.

Keep in mind that md5 is BROKEN. Also... sha1, sha256, sha512 and all other raw primitive hashes are BROKEN for password storage because they are CPU friendly. So what can we do? For starters unique salt per user and iterate it quite a lot:
while(i++ <= 1000)
hash = md5(i + salt + password)

Slowing it down intentionally helps quite a lot.
@ 50 GPU cluster:
6 char passwords will be cracked in 8 minutes, 7 in 12 hours, 8 in 62 days and whole English dictionary in 4 seconds. Still, better results needed.
hash = hash_pbkdf2 ( 'sha512' , password , salt , 10000, 40 )

@50 GPU cluster:
6 char passwords will be cracked in 14 days, 7 in 3.5 years, 8 in 350 years and whole English dictionary in 1.5 minutes.

Even more, using BCrypt algorithm based on Blowfish cipher is much harder to run on a GPU.
Also, php 5.5 has a password hashing API: https://gist.github.com/nikic/3707231

Hope this helps.

No comments

Leave a comment