Elliot Haughin

Weblife

Thoughts

Tunes

  • 18 hours agoHillsong – Stronger
  • 18 hours agoHillsong – High And Lifted Up
  • 18 hours agoHillsong – He Is Lord
  • 18 hours agoHillsong – This Is Our God
  • 18 hours agoHillsong – Desert Song
  • 18 hours agoHillsong – Run
  • 2009/01/05Hillsong – Run
  • 2009/01/05Hillsong – Home
  • 2009/01/05Hillsong – Run
  • 2009/01/05Hillsong – Home

Handling Passwords In CodeIgniter

Posted by Elliot on Sunday, February 17th, 2008

After an extremely long debate over at the CodeIgniter Forums, I’ve decided to compile the ‘outcome’ of this discussion here, and show you all the best practices for storing passwords in CI.

First of all, we need to make sure that the password sent from the user to us is encrypted, so that prying eyes cant get hold of it at this stage. So, the simple solution is to use SSL.
SSL allows https request data between the client and server, which is encrypted and very secure.

Now with that out of the way, we need to store the user’s password in the database.

Some people are currently using CodeIgniter’s ‘encryption’ library to store the passwords in the database. However, a password stored in the database should always be saved with 1-way encryption… so there is no-way to convert it back to the original plain-text version.

The solution, is a salted hash.

Essentially, you should use a 1-way hasing algorithm (like sha1), and ’salt’ the process.

Let me explain:

First we need a ’salt’… which is basically like a random bit of data we use with every password hash… we’ll use CodeIgniter’s ‘encryption_key’ config item to store this.

This should be 32 characters long, and upper and lowercase letters with numbers for good measure too.

$config['encryption_key'] = "NeO5C88iv7uo09U2E20iJF0iUiz8R9zm";

Now that we have our encryption key set… we build a little function for ‘prepping’ the password before we insert/select it from the database:

function _prep_password($password)
{
     return sha1($password.$this->config->item('encryption_key'));
}
 
function login($username, $password)
{
     $this->db->where('username', $username)l
     $this->db->where('password', $this->_prep_password($password));
 
     $query = $this->db->get('users', 1);
 
     if ( $query->num_rows() == 1)
     {
           // set your cookies and sessions etc here
           return true;
     }
 
     return false;
} 
 
function register($username, $password)
{
$data = array('username' => $username, 'password' => $this->_prep_password($password));
$this->db->insert('users', $data); 
}

So, what happens here, is that the password we save is modified using the sha1() function… but, we append our key to the password inside of this function so that we don’t end up with the ’standard’ hash for that string…

This way, we avoid the possibility of dictionary attacks.

And, that’s it!

It’s simple, but exceptionally secure.

After this long debate, one of the forum members: adamp1, posted this little gem:

Let me just throw my view in. I have done a cryptography course at degree level. let me just say one thing, if you have a two way encryption algorithm it can be broken very easily. You don’t even need the key, if you know how it works (the algorithm) most can be broken by simple processes.

If someone really wants some data you store they will be able to get it, doesn’t matter how much you encrypt it. The only way you can stop it is to make the process so hard the data isn’t worth it to decrypt it.

I store my passwords using a SHA-1 with salt method. I would advice you all to do the same. DO NOT use two way encryption just so the password can be made into ****’s. This is crazy, just say to the client NO. Your the expert they should listen to you, and if they still refuse print out a random length string of **’s or something.

So just to clarify, use SHA-1 with salt, its the best there is at the moment. I know SHA-1 has been broken but unless your a crypto-geek its probably the best and easiest to use.

Posted in: codeigniter, dev, php.

13 Responses to “Handling Passwords In CodeIgniter”

  1. Michael Wales Says:

    Excellent post Elliot and something I have covered once before on my blog as well: Handling Forgotten Passwords.

  2. Jakob Buis Says:

    I always use one-way encryption in both my personal and professional projects.

    Normally, the client doesn’t bother with how passwords are stored (that’s my job), as long as I keep his data perfectly safe.

    However, I don’t approve of adamp1’s point:
    In the rare case, that your client requires that you store passwords using two-way-encryption, you’d better not tell him you did so, if you didn’t. In Holland (the best country in the world ;) ), that could even be considered a breach of your contract.

    Not convinced? Naturally, when passords are stored using two-way encryption, your client will require that you can retrieve his password (which he forgot…again) instantly…now you’ve got yourself a neat, little problem.

  3. Elliot Says:

    if you have to use 2-way encryption, I’d do it using mysql’s aes_encrypt function

  4. CodeIgniter Framework :: TermiT's Blog Says:

    [...] Handling Passwords In CodeIgniter [...]

  5. Martin Cochran Says:

    I’m getting my PhD in cryptographic hash functions in about a month, have google alerts set up on the keyword ‘SHA-1′, and for some reason have felt compelled to point out some minor issues on otherwise very helpful posts like these.

    - SHA-1 is currently only theoretically `broken,’ although I would bet that collisions are found within the next year and a half. Even so, with salts and/or keyed hashes, there is little threat to this system. SHA-256 or SHA-512 are more secure alternatives for those truly paranoid.

    - Salted passwords usually use a distinct salt for each password. This scheme above seems to have one global salt. If you’re going to use a global salt, it is a good idea to treat it as a key because if it is found, a dictionary attack then becomes possible. (There are a whole host of issues with key management, though (http://en.wikipedia.org/wiki/Key_management).)

    - IF you go with the global key AND an attacker doesn’t find the key, then you’re probably OK.

    - Encrypting passwords with a non-one-way function like SHA-1 is discouraged because, again, you need to manage keys. Just know the can of worms you open when you agree to do key management.

    - Or you can use a different salt (ideally 16+ characters) with each user, and not worry about keeping these secure because they still prevent a dictionary attack. And make sure your salts are generated with a good RNG (openssl rand -base64 16, eg).

  6. Martin Cochran Says:

    I misspoke in the second-to-last bullet. It should read - “…with a non-one-way function like AES in some mode of operation is discouraged…”

  7. Elliot Says:

    You mentioned using a different salt for every user…

    How about this idea?

    Take their name and the global_salt… and sha1 that to produce a unique salt for that user…

    Use that to salt up the password hash.

  8. Martin Cochran Says:

    Using the username instead of an individual salt will effectively thwart dictionary attacks, with a couple of very small caveats.

    - The space of usernames is likely, in practice, much smaller than the space of salts generated with “openssl rand -base64 16″. Maybe this isn’t a such a big deal, but my paranoid security side has to ask the question of whether or not the same technique is used 10 years from now when computers have, say, 100 times as much processing power…

    - The system needs to gracefully handle a user changing usernames while keeping the same password. This isn’t a difficult problem to overcome, but is worth mentioning.

    Another possibility altogether I forgot to mention: using SSL to transfer the password, although secure, will require expensive public-key crypto operations. With this as the case, you might think of scrapping SSL and this custom password hash and use SRP (http://srp.stanford.edu/). It is a well-thought-out and vetted protocol that also allows the exchange of a shared secret. Weak passwords are protected, even with a very powerful adversary.

    It might seem like using something like SRP akin is using a tank where a hatchback will do, but that never stopped James Bond from using the tank.

  9. Hendrik Says:

    Elliot, I take the timestamp of when the user was entered into the db and use it together with the global salt. At least now I don’t have to anticipate the user changing her username as the timestamp never changes.

  10. Michael Wales Says:

    I just use CodeIgniter’s string helper to create a random string of X characters long and store that with the user’s record - giving each user a different salt.

  11. Some CodeIgniter Tutorial links « Afruj’s Weblog Says:

    [...] Handling Passwords In CodeIgniter [...]

  12. CodeIgniter Tutorial Links « Brandontruong’s Weblog Says:

    [...] Handling Passwords In CodeIgniter [...]

  13. Блог World Programs » Архив блога » CodeIgniter Framework Says:

    [...] Handling Passwords In CodeIgniter [...]

Leave a Reply

Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008Christmas 2008