-
BilltheCat Gravity is a harsh mistress.
  
-
Posts: 75
Threads: 13
Joined: Feb 2018
Reputation:
1
Yes, sorry, I have a text file of a few fake passwords that I've been copy/pasting to test and just grabbed a different one this time.
The login method already has a check on the password matching, and the function used is basically just password_verify but also fails over to crypt on PHP < 5.5.
PHP Code: public function check_passwd( $hash, $password ) { if( is_php('5.5') && password_verify( $password, $hash ) ){ return TRUE; }else if( $hash === crypt( $password, $hash ) ){ return TRUE; }
return FALSE; }
So now I have two checks on the password validating in the login method:
PHP Code: // Confirm user if( ! $this->_user_confirmed( $auth_data, $requirement, $passwd ) ) { // Login failed ... log_message( 'debug', "\n user is banned = " . ( $auth_data->banned === 1 ? 'yes' : 'no' ) . "\n password in database = " . $auth_data->passwd . "\n supplied password match = " . ($this->check_passwd( $auth_data->passwd, $passwd ) ? "True" : "False") . "\n Password Validation = " . (password_verify($auth_data->passwd, $passwd) ? "Passed" : "Failed") . "\n required level or role = " . ( is_array( $requirement ) ? implode( $requirement ) : $requirement ) . "\n auth level in database = " . $auth_data->auth_level . "\n auth level equivalant role = " . $this->roles[$auth_data->auth_level] ); }
Logs:
Code: DEBUG - 2020-08-04 23:20:26 -->
password stored in DB = $2y$11$8oe4JRwsm1LK1S8MqPd0sOQobASUdOIzx.KeFXO5bT.Tm.Ar5h86.
DEBUG - 2020-08-04 23:20:27 -->
Password Validation = Passed
DEBUG - 2020-08-04 23:21:35 -->
string = admin
password = 1aA!@#%^&*()-_=+{};:,<.>
DEBUG - 2020-08-04 23:21:36 -->
user is banned = no
password in database = $2y$11$8oe4JRwsm1LK1S8MqPd0sOQobASUdOIzx.KeFXO5bT.Tm.Ar5h86.
supplied password match = False
Password Validation = Failed
required level or role = 1
auth level in database = 9
auth level equivalant role = admin
-
ojmichael Junior Member
 
-
Posts: 41
Threads: 0
Joined: Jul 2020
Reputation:
0
-
BilltheCat Gravity is a harsh mistress.
  
-
Posts: 75
Threads: 13
Joined: Feb 2018
Reputation:
1
08-05-2020, 08:38 AM
(This post was last modified: 08-05-2020, 09:23 AM by BilltheCat.)
(08-05-2020, 12:25 AM)ojmichael Wrote: The first argument to password_verify is the password, and the second argument is the hash. It looks like you have these reversed.
https://www.php.net/manual/en/function.p...verify.php
Good catch! That was a copy/paste error on my part for sure, and I didn't try a "good" password that would have shown the typo.
So I ran a couple of new tests, one that works, and one that doesn't. Here's the two log results with the different passwords:
Code: DEBUG - 2020-08-05 15:18:16 -->
string = admin
password = 1aA!@#%^&*()-_=+{};:,<.>
DEBUG - 2020-08-05 15:18:16 -->
user is banned = no
password in database = $2y$11$64JQMc2Z3D680ePi/5iee.YvFed4FS1/Jt4CMn3xfXlZjIM1o43/6
supplied password match = False
Password Validation = Failed
required level or role = 1
auth level in database = 9
auth level equivalant role = admin
Code: DEBUG - 2020-08-05 15:26:41 -->
string = admin
password = KA83**8!d#
DEBUG - 2020-08-05 15:26:41 -->
password in database = $2y$11$Plsgi0m6m7Np8ZP6VFyAf.C2EqcAbs5ZLjBH9uJZnXtgcZu3yXXVS
supplied password match = True
Password Validation = Passed
required level or role = 1
auth level in database = 9
auth level equivalant role = admin
(08-04-2020, 11:12 PM)jreklund Wrote: Okay, try to log the password before "password stored in DB". That are the only place I can think about it being changed. As it looks correct on everything else.
I think we have a winner!
user_model log:
Code: DEBUG - 2020-08-05 15:35:25 -->
password before DB = 1aA!@#%^&*()-_=+{};:,<.>
DEBUG - 2020-08-05 15:35:25 -->
password stored in DB = $2y$11$s4QbphN38IDNphpnG/g4d.nvPsCMgjtKi.UEgPNvKerTDu3yH.kk2
DEBUG - 2020-08-05 15:35:25 -->
Password Validation = Passed
authentication log:
Code: DEBUG - 2020-08-05 15:40:05 -->
string = admin
password = 1aA!@#%^&*()-_=+{};:,<.>
DEBUG - 2020-08-05 15:40:06 -->
user is banned = no
password in database = $2y$11$s4QbphN38IDNphpnG/g4d.nvPsCMgjtKi.UEgPNvKerTDu3yH.kk2
supplied password match = False
Password Validation = Failed
required level or role = 1
auth level in database = 9
auth level equivalant role = admin
Confirmed.... the issue is that my change_password method is using html_escape, but my login method was not. Updated the login method, and it works as expected for all passwords.
Thanks for all your helpful suggestions!
-
InsiteFX Super Moderator
     
-
Posts: 6,733
Threads: 345
Joined: Oct 2014
Reputation:
246
-
BilltheCat Gravity is a harsh mistress.
  
-
Posts: 75
Threads: 13
Joined: Feb 2018
Reputation:
1
08-05-2020, 01:33 PM
(This post was last modified: 08-05-2020, 02:04 PM by BilltheCat.)
(08-05-2020, 12:24 PM)jreklund Wrote: You should not use html_escape at all. As the user supplied password have been altered.
You should only escape on output not input.
Yeah, I've been thinking about that, and didn't like it. It came that way from community_auth but I'm changing it as you suggest.
PHP Code: $this->_change_password( set_value('passwd', '', FALSE), //wasn't FALSE by default set_value('passwd_confirm', '', FALSE), //wasn't FALSE by default set_value('user_identification'), set_value('recovery_code') );
It looks like I have an old version.... just checked out community_auth on bitbucket, and he's updated the section.
PHP Code: $this->_change_password( $this->input->post('passwd'), $this->input->post('passwd_confirm'), set_value('user_identification'), set_value('recovery_code') );
-
InsiteFX Super Moderator
     
-
Posts: 6,733
Threads: 345
Joined: Oct 2014
Reputation:
246
08-13-2020, 08:06 AM
(This post was last modified: 08-13-2020, 10:44 AM by InsiteFX.)
Here are working examples of password_hash(), password_verify() and password_needs_rehash().
Controller: HashGenerator.php
PHP Code: <?php namespace App\Controllers;
/** * Class HashGenerator Controller * * @package App\Controllers */ class HashGenerator extends BaseController { /** * Class properties go here. * ------------------------------------------------------------------- * public, private, protected, static and const. */
/** * @var array - Holds the view file data */ public $data = [];
/** * @var string - Yoour password to hash. */ protected $password = 'password';
/** * @var - The hashed password */ protected $hash;
/** * @var - The stored hash. */ protected $stored;
// -------------------------------------------------------------------
/** * __construct () * ------------------------------------------------------------------- * * Class Constructor * * Do not use this for Production without security in place. * * NOTE: Not needed if not setting values or extending a Class. * */ public function __construct() {
}
// -------------------------------------------------------------------
/** * index () * ------------------------------------------------------------------- * * NOTE: The database password field should be VARCHAR(255). * */ public function index() { $cost = 12;
// Hash the password. $this->hash = $this->passwordHash($cost, $this->password); $this->stored = $this->hash; echo 'Password Hashed = '.$this->hash.'<br>';
// Verify the password. $this->hash = $this->passwordVerify($cost, $this->password, $this->hash); echo 'Password Verify = '.$this->hash.'<br>';
// Changed cost - password needs rehash. Generates a new password hash. $cost = 11; $this->hash = $this->passwordVerify($cost, $this->password, $this->stored); echo 'Password Verify Rehash = '.$this->hash; }
// -------------------------------------------------------------------
/** * passwordHash () * ------------------------------------------------------------------- * * @param int $cost * @param string $password * @return false|string|null */ protected function passwordHash(int $cost, string $password) { // The cost parameter can change over time as hardware improves $options = [ 'cost' => $cost, ];
return password_hash( base64_encode( hash('sha256', $password, true) ), PASSWORD_DEFAULT, $options ); }
// -------------------------------------------------------------------
/** * passwordVerify () * ------------------------------------------------------------------- * * @param int $cost * @param string $password * @param string $hash * @return false|string|null */ protected function passwordVerify(int $cost, string $password, string $hash) { $newHash = '';
// The cost parameter can change over time as hardware improves $options = [ 'cost' => $cost, ];
// Verify stored hash against plain-text password if (password_verify(base64_encode(hash('sha256', $password, true)), $hash)) { // Check if a newer hashing algorithm is available or the cost has changed if (password_needs_rehash($hash, PASSWORD_DEFAULT, $options)) { // If so, create a new hash, and replace the old one $newHash = password_hash( base64_encode( hash('sha256', $password, true) ), PASSWORD_DEFAULT, $options ); }
// Update the users database record. password = $newHash
// Then login the user
// Used for the example, can remove later. return $newHash; } }
// -------------------------------------------------------------------
} // End of HashGenerator Controller Class.
/** * ----------------------------------------------------------------------- * Filename: HashGenerator.php * Location: ./app/Controllers/HashGenerator.php * ----------------------------------------------------------------------- */
I hope this helps other to understand how the password routines operate.
The Controller is a CI 4 Controller but you should be able to copy everything to a CI 3 Controller.
What did you Try? What did you Get? What did you Expect?
Joined CodeIgniter Community 2009. ( Skype: insitfx )
|