Handle Passwords Securely: Storage
Mathew Davies was recently featured on Community Voice (Elliot Haughin and myself were featured in past articles) where he discusses some of the security features within his Redux Authentication library. In his Community Voice he even took the opportunity to mention an article I wrote before the crash of 2008, referencing how to handle a user’s forgotten password.
I’ve taken this as a note to rewrite that article as well as to extend it a bit…
Computer systems in general and your web application especially, never store passwords in plain-text. This is a very basic concept - if you don’t quite grasp the reason behind not storing passwords as plain-text I’ll take the stance of security expert Matasano Chargen and advise you to use someone else’s security system (Redux, for instance).
I’m sure we are all aware of the fact we should not be storing passwords at all; rather, we should be storing a hashed string representing that password. By hashing the password, we theoretically create a one-way encryption mechanism whereby the original password can not be restored. We then validate users by using the same hashing algorithm on their input and check if the two hash strings match.
Let’s look at the following code for example:
function password_check($password) {
// This is the valid password hash - let's pretend it came from a database
$v_password = 'af2c41eb4e034ed0a417d1ec637082072a4d3aae';
// Load our security helper, so we can use the sha1() function
// if our server doesn't have it already.
$this->load->helper('security');
// Check if the hash of the passed password === the valid password hash
if (sha1($password) === $v_password)) {
return TRUE;
}
return FALSE;
}
Now, I bet you are looking at that string af2c41eb4e034ed0a417d1ec637082072a4d3aae and thinking, “Man, that’s pretty secure! There’s no way I could guess what that password is.”
Let me show you a little trick, thanks to our good friend Google. A quick search for that hash string returned this text file, that has loads of hash strings for a variety of English words. One of those words happens to be wizard, which also happens to be our password.
So, if we can’t hash a string and be safe - what are we to do?
The most common method of securing a user’s password is by adding a little salt. By assigning each user a random string (the salt) and appending that to the password string, prior to hashing it, we have significantly improved our security.
Using the same code example as above, but now adding in the salt:
function password_check($password) {
// This is the user's salt - which we pulled from a database
$salt = 'Pr8Qm7ahY';
// This is the valid salt + password hash - let's pretend it came from a database
$v_password = '2dab11e9958c2e785ec6dbaaa4fc461969531b01';
// Load our security helper, so we can use the sha1() function
// if our server doesn't have it already.
$this->load->helper('security');
// Check if the hash of the passed password === the valid password hash
if (sha1($salt . $password) === $v_password)) {
return TRUE;
}
return FALSE;
}
The first thing you should have noticed is our valid password hash changed - significantly. I invite you to Google that string - you won’t come up with any results (well, maybe this page after the GoogleBot pays me a visit - but nothing worthwhile).
So, is it unstoppable? Absolutely not - by no means. I think it’s safe to say that any string that is encrypted can eventually be decrypted. Security isn’t a practice in making an unstoppable algorithm, you simply need to create an algorithm in which the return is not worth the time invested in cracking it.
The password within this system could easily be cracked by simply hashing every possibly combination of characters. Using our salt + password (which is 15 characters) and our character set ([a-zA-Z0-9]) there are 2.40656038 × 1073 possible combinations.
I ran the following code on my laptop 5 times, within the CodeIgniter framework, to come up with an estimation as to how many 15-character SHA1 hashes your average computer could process. Please bare with me, I realize this is a fairly arbitrary number that could be astronomically improved by changing any of the included variables (compiled low-level language, dedicated system, more RAM, faster processor, etc). Additionally, I am hashing a randomized string each pass rather than incrementing one of the character positions in a structured manner (which is the preferred method of a brute-force attack of this nature).
function time_sha1($loops = 10000) {
$this->load->helpers(array('security', 'string'));
$this->benchmark->mark('loop_start');
for ($i = 0; $i < $loops; ++$i) {
sha1(random_string('alnum', 15));
}
$this->benchmark->mark('loop_end');
echo $this->benchmark->elapsed_time('loop_start', 'loop_end');
}
This gave me an average of 0.65142 seconds per 10,000 hashes, or 15,351 per second. So… on my little laptop I would only make it through 484,430,371,026 after a year of searching! It would take 4.96781483 × 1061 years to test out every combination (and that is assuming I knew the length of the hash and password together was 15 characters).
There are definitely some good conversations discussing the merits of slower encryption methods (mcrypt and bcrypt, for instance). The slower your encryption method the more secure your application is from a brute-force attack of this nature, but (and take this for what it is worth) in my experience and in my past projects, I have had little need to go beyond the salt + password hash algorithm. Of course, this all depends on the application you are working with - banks, government agencies, corporate intranets? Sure, you have the horsepower and the need for a higher level of encryption than most of us will ever need.
Next time: What to do when a user forgets their password.

Hi Michael,
Is there any chance you could post up your Erkana Auth? I can’t find any reference anywhere to it, except for here.
Cheers, Cameron.
Oh, I should’ve added to the other post:
Or do you recommend Redux Auth?
Cameron.
@Cameron
I can’t personally recommend Redux as I have never used it but, based on what I have heard and the fact that Derek Allard has nothing to say but good things about it - it’s definitely worth looking into.
I have an upcoming project that will require user authentication. At that time I intend to try out Redux and if it doesn’t bode well for me I will rewrite Erkana and post it.
Until then - there are a few posts on the forums with the full source.
Thanks Michael for this very interesting article. If you could do the same about sessions (security, storing in database, regenerating ids…), it would be really helpful for the Code Igniter community I think.
A very good article indeed. I can only agree that salt + hash is all most of us will ever need. There are bigger problems than brute force attacks out there.
I noticed some odd referrers coming from this article to my old blog. And while I certainly appreciate the link, you have the wrong url for Mathew’s website. He has http://www.leveldesign.info/ listed in his CI profile, although I don’t know how up-to-date that is.
While I’m at it, your comment form doesn’t quite render correctly in Safari. It’s just the slightest bit too wide so it slides below the other fields.
Thanks for noticing that Inparo, but I have just launched my portfolio website http://www.mathew-davies.co.uk
It’s still being developed, but you should point the link there for future references.
Michael, It made me genuinely smile when you said Derek Allard had nothing bad to say about it. It means a lot to me to hear some one well known as Derek to like one of my addons.
I also look forward to seeing what you to have to say about Redux Authentication
Ps : It’s Mathew with one “t”
Thanks for the updates guy - I’ve changed the link as well as the spelling of your name.