zondag 6 december 2009
Posted in
authentication
,|
codeigniter
,|
security
|
0
reacties
For my 'dayjob'-cms I wrote a very lightweight CodeIgniter authentication library. Right now it contains a few options:
Most existing authentication systems on websites have a few weaknesses.
Encryption works sorta like this: You send your password, your password is encrypted using a key, and the key is used to decrypt the password back to it's original form. Not so secure, since when somebody finds out about the key, or knows the algoritm, you're passwords are in the open.
Hashing is more secure. You 'hash' a password, and it becomes this very unreadable string (like 58cb9c42406324cce492640a0c20d8da) and to check if a user entered the correct password, you will hash the entered password and compare it to the hash in the database.
Code example:
One big problem: no matter what, the hashing of my password: 'f@bdrolrules!' (obviously without the quotes) always returns the same hashed string: '97e2163bbd1139bfb695031767249fb06c56d112'. (also without the quotes). So if the girl next door (I live in a student house, next door lives this very beautiful girl) happens to think of me like I do, and her password to my great app is also 'f@bdrolrules!', those hashes would be the same. Not really secure, 'cause when I use this password all over the internet, the internet will be flooded with this hash '97e2163bbd1139bfb695031767249fb06c56d112' connected to my name in lot's of databases.
Well, most people wouldn't see that as a big risk, but it actually is. It's much more secure to 'salt' it, meaning that every time you register with that one password, the hash will be different.
The code below is a simple, yet very secure, method for hashing password. Unlike the code before, this should work on any PHP setup, not just in CodeIgniter.
So, that's nice. But how do we check and register stuff then?
A bit clear now? twitter me for questions. (@fabdrol)
- Registration
- Login
- Logout
- Groups
- Very Secure Hashed Passwords
Most existing authentication systems on websites have a few weaknesses.
- Encryption (2 way)
- Password retrieval
- Weak passwords
Encryption works sorta like this: You send your password, your password is encrypted using a key, and the key is used to decrypt the password back to it's original form. Not so secure, since when somebody finds out about the key, or knows the algoritm, you're passwords are in the open.
Hashing is more secure. You 'hash' a password, and it becomes this very unreadable string (like 58cb9c42406324cce492640a0c20d8da) and to check if a user entered the correct password, you will hash the entered password and compare it to the hash in the database.
Code example:
$db = $this->db;
$in_mail = $this->post->input('email', true); // second parameter checks
$in_pass = $this->post->input('password', true); // for xss scripting
$db->where('email', $in_mail);
$db_get = $db->get('users');
if($db_get->num_rows() == 1) {
$db_row = $db_get->row();
} else {
echo "user doesn't exist";
exit();
}
if($db_row->password == sha1($in_pass)) {
// password true, we used sha1 as hashing function
// do login logic and stuff
echo "you're logged in";
}
One big problem: no matter what, the hashing of my password: 'f@bdrolrules!' (obviously without the quotes) always returns the same hashed string: '97e2163bbd1139bfb695031767249fb06c56d112'. (also without the quotes). So if the girl next door (I live in a student house, next door lives this very beautiful girl) happens to think of me like I do, and her password to my great app is also 'f@bdrolrules!', those hashes would be the same. Not really secure, 'cause when I use this password all over the internet, the internet will be flooded with this hash '97e2163bbd1139bfb695031767249fb06c56d112' connected to my name in lot's of databases.
Well, most people wouldn't see that as a big risk, but it actually is. It's much more secure to 'salt' it, meaning that every time you register with that one password, the hash will be different.
The code below is a simple, yet very secure, method for hashing password. Unlike the code before, this should work on any PHP setup, not just in CodeIgniter.
private function _hash($mail, $pass, $salt = false) {
if($salt == false) {
// no salt supplied, so we will generate a new one
$salt = $this->_salt();
}
// $private_key: a 32 char string only known inside your code
// write it down, without it every password in your db will be useless
$private_key = '678bb87f4bfb15f5ed3bf49f722e1c15';
$unhashed = $mail . $pass . $private_key . $salt;
$hashed = sha1($unhashed);
// return the hash AND the salt, for saving into the db.
return array('secure_password' => $hashed, 'salt' => $salt);
}
private function _salt() {
// function to do some stuff and generate a hash that nobody can guess.
// and I mean nobody, even not the beautiful girl next door ;-)
$rand = time().mt_rand();
$uniek = uniqid($rand, true);
return sha1($uniek);
}
So, that's nice. But how do we check and register stuff then?
public function register($mail, $pass) {
$hashed = $this->_hash($mail, $pass);
$user['email'] = $mail;
$user['password'] = $hashed['secure_password'];
$user['salt'] = $hashed['salt'];
// saving the req. data for authentication:
// email (= username), password -- in ultra secure hashed form -- and salt, to check passwords.
}
public function check_pass($mail, $pass) {
$db_salt = $this->_get_salt_from_db_where_email_is_supplied_email($mail);
$db_pass = $this->_get_pass_from_db_where_email_is_supplied_email($mail);
// run hash function, supplying the salt (saved in database)
$hash_arr = $this->_hash($mail, $pass, $db_salt);
// check hashed supplied password against hashed password from DB
if($hash_arr['secure_password'] === $db_pass) {
// using triple === so not only the contents of the hash are the same,
// also the type (string) needs to be the same.
echo "logged in";
// do session magic and stuff
}
}
A bit clear now? twitter me for questions. (@fabdrol)