Codeigniter authentication library 3/3
Further implementation
In the previous part of the authentication library posts I explained how to generate a secure token for each user and the basic functions that are needed to create and delete the cookie.
To summarize:
- Using a global secret_key constant and the user id we generate a unique key for each user that is used to encode the final token. Using a different key for each user makes it a lot harder to decipher the keys. The strength and length of the token depends on what cryptographic function is used.
- When the token found inside the cookie matches the new generated token the user is logged in. To have a complete library we need a few more functions:
The authenticate function:
public function authenticate($username, $password, $remember = FALSE) {
$query = $this->CI->db->query("SELECT * FROM `users` WHERE `username` = " . $this->CI->db->escape($username));
if ($query->num_rows() == 1) {
$user = $query->row_array();
$password = $this->password_hash($password);
if ($password == $user['password']) {
$this->create_cookie($user['id'], $remember);
return TRUE;
}
}
return FALSE;
}
private function password_hash($password) {
return hash_hmac("sha512", "salt" . $password,$this->secret_key);
}
These are basic functions that you can extend to your specific environment. The authenticate function checks the database if there is a user that matches the username and compares the hashed passwords.
The passwords are hashed using the password_hash function. What this functions does with the passwords is your own choice. I chose to concatenate a salt and then use the SHA2 method to hash it. Using a salt protects you against so called "rainbow tables".
Loggedin?
With our secure cookie we only have to check the cookie's content using the function created in the previous part. This is an example how it could look like:
public function __construct() {
/* Other stuff */
$this->CI = &get_instance();
$this->loggedin = $this->verify_cookie();
}
public function loggedin() {
return $this->loggedin;
}
public function logout() {
$this->loggedin = FALSE;
$this->delete_cookie();
}
When our authentication class object is created it automatically checks if a cookie token is present. The token is checked and the value of 'loggedin' is adjusted accordingly.
The only thing the public loggedin function has to do is return the loggedin value.
Controllers
Your login controller could look like this:
class Login extends Controller {
function index() {
if ($this->auth->loggedin())
redirect('admin');
else
$this->load->view('admin/login');
}
function authenticate() {
$username = $this->input->post('username');
$password = $this->input->post('password');
$remember = $this->input->post('remember') ? TRUE : FALSE;
if ($this->auth->authenticate($username, $password, $remember))
redirect('admin');
else
redirect('admin/login');
}
}
If you visit the login page it will decide whether to display a login form or redirect you if you are logged in. The authenticate function is your form action which will check the form's values and authenticates the user.
Final words
To be honest, this method of storing tokens in a cookie is not hack proof, but it is not easy. Rainbow tables and dictionaries won't work and neither will reverse-engineer methods to crack the keys since every user has his own unique key. A possibility to crack to token is in fact guessing it. By adjusting the cookie's content it is possible to guess a valid token for a specific user. But if you use the SHA512 method to generate the token there are 64^16 possibilities and that is quite a lot.
If you want a super protected website you must use a sessions database table so that you can check if the cookie values are manipulated or not.
If you have any suggestions or questions about the authentication library don't hesitate to contact me.