Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a more secure hashing algorithm with CakePHP

By default, CakePHP seems to use the SHA1 algorithm to hash passwords and only seems to offer SHA256 as an alternative:

http://api.cakephp.org/view_source/security#line-86

I wanted to switch to a more secure password hashing solution before I make my application public to save future headaches when switching to a more secure hashing algorithm. I've looked around for some guides on using bcrypt or something similar but they all seem to be for older versions of Cake, or implement the hashing poorly.

Is there a guide somewhere that can show me how to integrate better password hashing without changing any code in my models or controllers?

Also, a little side question, why did the Cake devs only include SHA password hashing in their release? It's common knowledge that SHA is a broken hashing algorithm for passwords, it just seems to me that such a reputable framework wouldn't have overlooked this.

like image 903
James Dawson Avatar asked Jul 27 '12 04:07

James Dawson


1 Answers

In this ticket CakePHP contributor Mark Story mentions that bcrypt will be supported in CakePHP 2.3 (yet to be released) and will become the standard/default in 3.0.

Also, in this blog post Mark talks about what changes are needed to use bcrypt in CakePHP 2.0. Seems relatively minor, although will require changes to your user model.

Borrowing the code from that post, what Mark did was created a subclass of FormAuthenticate:

<?php
App::uses('FormAuthenticate', 'Controller/Component/Auth');

class BcryptFormAuthenticate extends FormAuthenticate {

/**
 * The cost factor for the hashing.
 *
 * @var integer
 */
    public static $cost = 10;

/**
 * Password method used for logging in.
 *
 * @param string $password Password.
 * @return string Hashed password.
 */
    protected function _password($password) {
        return self::hash($password);
    }

/**
 * Create a blowfish / bcrypt hash.
 * Individual salts could/should used to be even more secure.
 *
 * @param string $password Password.
 * @return string Hashed password.
 */
    public static function hash($password) {
        $salt = substr(Configure::read('Security.salt'), 0, 22);
        return crypt($password, '$2a$' . self::$cost . '$' . $salt);
    }
}

Then made an update to the controller components array:

<?php
public $components = array(
    'Auth' => array(
        'authenticate' => 'BcryptForm',
        // other keys.
    )
);

And finally updating the User model's beforeSave callback:

<?php
App::uses('BcryptFormAuthenticate', 'Controller/Component/Auth');

class User extends AppModel {
    function beforeSave() {
        if (isset($this->data['User']['password'])) {
            $this->data['User']['password'] = BcryptFormAuthenticate::hash($this->data['User']['password']);
        }
        return true;
    }

}
like image 54
Robert Groves Avatar answered Sep 28 '22 00:09

Robert Groves