My goal is to have a unique salt for each user rather than just using Configure::read('Security.salt')
for every user.
I know that CakePHP 2.x no longer hashes passwords automatically. This allows me to perform model validation on passwords, which is very nice. However, I don't see a way that I can override the AuthComponent's "password" method. So even though I can control how passwords are hashed before they are saved to the database, I cannot control how passwords are hashed when performing the actual login. From the cookbook:
You don’t need to hash passwords before calling
$this->Auth->login()
.
What can I do to make $this->Auth->login()
use a custom method of password hashing?
Thanks.
UPDATE: I ended up going with dr Hannibal Lecter's answer (creating a custom authentication object). Here's how to do it:
Old code:
$this->Auth->authenticate = array('Form' => array('fields' => array('username' => 'email')));
New code (change "Form" to "Custom"):
$this->Auth->authenticate = array('Custom' => array('fields' => array('username' => 'email')));
Create "app/Controller/Component/Auth/CustomAuthenticate.php" and make it look like this:
<?php
App::uses('FormAuthenticate', 'Controller/Component/Auth');
class CustomAuthenticate extends FormAuthenticate {
}
Copy the "_findUser" and "_password" methods from "lib/Cake/Controller/Component/Auth/BaseAuthenticate.php" and paste them into the "CustomAuthenticate" class. Then make the following two modifications to the "_findUser" method:
Remove this line from the "$conditions" array: $model . '.' . $fields['password'] => $this->_password($password),
Change if (empty($result) || empty($result[$model])) {
to if (empty($result) || empty($result[$model]) || $result[$model][$fields['password']] != $this->_password($password, $result[$model]['id'])) {
Then make the following two modifications to the "_password" method:
Create the "$id" parameter by changing protected function _password($password) {
to protected function _password($password, $id) {
Update the salt value by changing return Security::hash($password, null, true);
to return Security::hash($password, null, Configure::read('Security.salt') . $id);
Lastly, update all occurrences of AuthComponent::password
to use Security::hash
with the same logic as above.
You could probably create a custom auth object and hash the password however you like. Take a look at the existing auth objects to get the general idea of how they work.
Have you considered not using Auth->login() call but rather using the code from the current implementation in your model? (http://api20.cakephp.org/view_source/auth-component#line-506) You could rewrite this to suit your needs.
For anyone wanting more information on why salting each password is the right way to hash passwords (w/code examples), visit here: http://crackstation.net/hashing-security.htm.
Perhaps a slight improvement to the code posted here is to take the advice of the article I just linked to, and to generate a "new random salt" ... "each time a user creates an account or changes their password."
The implementation posted here uses a combination of the original Auth's hard-coded static salt plus the user ID as the salt which means that the same salt gets re-used for each user whenever they change their password. So if you want to follow the recommendations of this hashing guide, you need to generate a new random salt each time the user creates/changes their password, and must store that unique salt in the users table along with the hashed password.
You could use their random salt generator:
define("PBKDF2_SALT_BYTES", 24);
$salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
and by convention, store it in the users table in a new field named 'salt'. Since the code already gives you the user id, you can always store/lookup the salt as needed.
Also mentioned in the article is a section on "Slow Hash Functions" using a technique known as "key stretching" and how to implement using standard algorithm like PBKDF2 or bcrypt. PHP code examples are provided which can be copied and pasted into your custom Auth implementation for added security.
CakePHP developer Mark Story has posted a blog entry on how to implement bcrypt in CakePHP's Auth
In the comments section, Mark Story commented that CakePHP 2.3 will have some new built-in features to generate bcrypt hashes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With