Welcome Guest, Not a member yet? Register   Sign In
Best way to handle passwords using CI library?
#1

[eluser]Chris.Campbell[/eluser]
I read this page and it shows some options: http://ellislab.com/codeigniter/user-gui...ption.html Which one is the recommended way to handle passwords, encrypting + salt, and then comparing the supplied pass with the one in the database, thanks in advance.
#2

[eluser]xwero[/eluser]
i use following method to check if the login is valid
Code:
function valid_login($username,$password)
{
    $query = $this->db->select('password')->from('users')->where('username',$username)->get();
    if($query->num_rows() == 0)
    {
        return false;
    }
    else
    {
       $this->load->library('encrypt');
       foreach($query->result as $row)
       {
          if($this->encrypt->decode($password) == $row->password)
          {
             return true;
          }
       }
       return false;
    }
}
note : this works only in php5. for php4 you need to split the building of the query statement and use result_array in the loop.
#3

[eluser]wiredesignz[/eluser]
Mine is almost identical to xwero

Code:
function try_login($attempt)    //$attempt is an object
{        
    if ($attempt->password)    
    {
        //find user, check password & create cookie if valid
        if ($user = $this->users->findBy("`username` = '{$attempt->username}'") AND $attempt->password == $this->encrypt->decode($user->password))    
        {
            set_cookie('ci_user', $user->uid, 0); //cookie expires on browser close
            if ($attempt->remember) set_cookie('ci_login', $user->uid, 86500);
            return TRUE;
        }
    }
    return FALSE;
}
#4

[eluser]Elliot Haughin[/eluser]
Hey guys...

Just wanted to make a few comments regarding passwords and security.

The ideal situation is to have a password saved in the database that CANNOT be converted back to plain text under any circumstance.

So, the best practice would be to do something like this:

First of all, set an encryption key in your config.php...
and make it nice and random using a random string generator like this one (make it 32 characters, upper and lower case, including numbers. (as recommended by the user guide)

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

Now write this down, and put it somewhere safe... and I mean physically write it down... like analogue, on paper....
Because all your passwords are going to use this, and if ever you lose your config.php file, you must restore it and put in the same key.

Now, let's look at the library.

Code:
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;
}

Using the 'encryption_key' at the end of the password means that your generated sha1 string will not be the same as the sha1 string for just the password on its own. (which stops dictionary sha1 attacks).

In the 'good old days', when the famous 'PHPNuke' was extremely popular, people would find SQL injection holes to run their own queries:
Code:
$search = $_POST['search'];

$query = 'select * from articles where title='$search';

But, if you post the search term:
Code:
'; select * from users where id = '1

the final sql would be:
Code:
select * from articles where title=''; select * from users where id = '1';

Then, by finding the password, (which was only encrypted using MD5($password) without a salt, the intruder could use a dictionary attack like:

Code:
$stolen_md5 = 'ainofdifdofij'; // Yes, I know an MD5 is only 0-9 and a-f chars.

foreach ($dictionary as $word)
{
    if (MD5($word) == $stolen_md5)
    {
        echo 'password is: '.$word;
        exit;
    }
}
So, by using a salt (the encryption key tagged on the end of your password)... the result sha1 is nothing like the sha1 for the password on its own. Stopping dictionary attacks.
And, the password, even if retrieved from the DB could not be converted back to a 'real' string, because sha1 is a 1-way hashing algorithm.

Simply using $this->encrypt->encode() is dangerous, because if someone gained your key, they have the means to convert your passwords back to plain text. (granted, it's not easy... but still possible).

when you insert a user:

Code:
$data = array('username' => $username, 'password' => $this->_prep_password($password));
$this->db->insert('users', $data);

So, there's a little example of a 'very good' practice when it comes to passwords and databases...
With an explanation into 'why' do it this way.

Hope this is useful.
#5

[eluser]wiredesignz[/eluser]
Very clever thanks Elliot.

Personally I do use the encryption salt. (Thanks to Micheal Wales comments a while back)

But I still like to display a string of * equivalent to the length of the real user password in the user account editor, this requires encrypt->decode to work.

Code:
$users_account->hidden_pwd = str_repeat('*', strlen($this->encrypt->decode($users_account->password)));

I'm sure I could use your idea and still provide that functionality.
#6

[eluser]Elliot Haughin[/eluser]
But... that's not how you should do it...

Keep with the 40 char super strong sha1 in the db, and let your interface suffer a little for the sakes of a huge security increase.

Just have:

Old Password:
New Password
New Password (again)

Text boxes.... And have them all blank as default.
This is how many of the 'big players' do it.

NEVER sacrifice security for usability or design...
It's false economy, your site wont look and feel as nice if it gets hacked.
#7

[eluser]Phil Sturgeon[/eluser]
Well the two are slightly different, I preffer the second. Putting both checks in the DB makes things alot quicker and reduces the code alot. Why not chuck in some insensitivity checks?

Code:
"LOWER(username)` = '".strtolower($attempt->username)."'")
#8

[eluser]xwero[/eluser]
I understand the security risks but from most clients we get the request to see the passwords from the users.
Because a lot of people just don't want to go through the whole request new password -> validate profile -> generate new password routine they just email the site admin to send their password.

It are real world situations that make you not use the most secure methods.
#9

[eluser]Elliot Haughin[/eluser]
Case insensitivity is a good idea...

But instead of doing:
Code:
"LOWER(username)` = '".strtolower($attempt->username)."'")

Just do:
Code:
$this->db->where('username', strtolower($username));

Then make your 'insert' convert the username into lowercase before it goes into the db.
That way, you know that all usernames in the DB are lowercase and you dont have to run LOWER() on every select request.
#10

[eluser]Phil Sturgeon[/eluser]
[quote author="Elliot Haughin" date="1203099391"]But... that's not how you should do it...

Keep with the 40 char super strong sha1 in the db, and let your interface suffer a little for the sakes of a huge security increase.

Just have:

Old Password:
New Password
New Password (again)

Text boxes.... And have them all blank as default.
This is how many of the 'big players' do it.

NEVER sacrifice security for usability or design...
It's false economy, your site wont look and feel as nice if it gets hacked.[/quote]

This is the same internal dialog I was having. CI's built in encode and decode functions seemed insecure to me, so I switched BambooInvoice to using SHA1, but then after a little while I realised they were actually just as secure. Yes the encode()'s strings can be decoded, but not if they are using an encryption key. With a key in your CI config file the encode/decode functions are JUST as secure as using SHA1, with extra benefits like being able to show the length of a password for the interface.

You can save yourself the prep_password() function by using the built in $this->encrypt->sha1() password, I believe that automatically includes the encyption key.




Theme © iAndrew 2016 - Forum software by © MyBB