Password Hashing in CakePHP
In a recent project I needed to add some validation to my User model. I’m using the Auth Component that is included with CakePHP. In this particular instance I wanted to allow a change password form. The form would have three fields (current_password, new_password, confirm_password). In the Model I wanted to first check if the current password was entered correctly.
Validation should always happen in the model so I created a new function that would check for the current password for the logged in user. The Auth component automatically hashes the password with SHA1 and uses the Security Salt as part of the password string to create the hash, so I needed to hash the “current_password” field from the form to check for a match. This is where I ran into the problem. I tried using the following:
function checkCurrentPassword($data) {
$id = $this->data[$this->alias]['id']; // passed the user ID from the form as a hidden field
$pwd = $this->field('password', array('id' => $id)); // get the current password from the database
if(Security::hash($data['current_password']) != $pwd) {
return false;
}
return true;
}
You can see that $id is passed from the form and $pwd is a variable for the current password in the database. Auth will automatically hash an input with the name “password”, but my form is using “current_password”, so it is sent in cleartext. This needs to be hashed first. I attempted to use the Security::hash function but my validated kept failing.
As it turns out the Security::hash function is only using SHA1 without the Security Salt added. What I was able to do is use the AuthComponent::password function instead which does use the Security Salt configured in core.php. New code looks like:
function checkCurrentPassword($data) {
$id = $this->data[$this->alias]['id'];
$pwd = $this->field('password', array('id' => $id));
if(AuthComponent::password($data['current_password']) != $pwd) {
return false;
}
return true;
}
The validate array would look like this:
var $validate = array(
'current_password' => array(
'rule' => 'checkCurrentPassword',
'message' => 'Current password was not entered correctly'
)
);
Update: Security::hash actually takes a third parameter documented in the API to use the Security.salt value
Create a hash from string using given method. Fallback on next available method.
Parameters:
string $string required
String to hash
string $type optional NULLMethod to use (sha1/sha256/md5)
boolean $salt optional falseIf true, automatically appends the application’s salt value to $string (Security.salt)
