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.




Excellent post Elliot and something I have covered once before on my blog as well: Handling Forgotten Passwords.
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:
), that could even be considered a breach of your contract.
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
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.
if you have to use 2-way encryption, I’d do it using mysql’s aes_encrypt function
[...] Handling Passwords In CodeIgniter [...]
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).
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…”
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.
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.
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.
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.
[...] Handling Passwords In CodeIgniter [...]
[...] Handling Passwords In CodeIgniter [...]
[...] Handling Passwords In CodeIgniter [...]
excellent article – thank you. i am a code igniter/PHP newbie (come from a java background), so am just learning the PHP way of doing things.
in principle tho, things remain the same. 1-way encryption is essential, and for users who need to “recover” their passwords – sorry, but no can do. i can reset it for you, but not recover – it’s a very small priice to pay for the security offered by sha1/salt.
i am not able to decrypt password please help me
Hello Eliot
The suggestion you provided is completely wrong. You are using codeigniter encryption process which generates different encryption key at a time.
Here the code you write with concatenating with codeigniter encryption key
$password.$this->config->item(’encryption_key’)
This Part $this->config->item(’encryption_key’) will generate different keys each and every time you run it.
My question is if do it and store it on database how the password will be same when a user will enter his /her plaintext password.
You may answer you will do the encryption again what the user inputs on the login form. It will never same again how you have done it when a user signups. So best practice is to use one way encryption process.
When a user asked for a lost password you can give it to him in other way
like reseting the password. asking his/her security question.then store a random password on database and on session. then ask him to change the password.
Actually, it won’t… it will get the $config['encryption_key']; value stored in application/config/config.php
So, that part is the same very time, and the encryption will work.
[...] in a database as a hashed value with a salt. This is demonstrated clearly in Elliot Haughin’s Handling Passwords In CodeIgniter post. These same principles can be applied to any type of PHP [...]