If you have experience with PHP and the Zend Framework, you should check out TomatoCMS. It’s a great content management system, with a lot of cool features. It may take a little getting used to, but it has quite a bit of “out of the box” potential for the base of a website. One great feature, which is provided by the framework, is the MVC design approach. There is however, a minor drawback in the authentication system. Fortunately, this drawback does not take much to improve.
Many of the websites I create I develop from scratch, using the Zend Framework. I’ve become accustomed to building login systems with salt/hashed passwords for quite awhile, because I like to believe that anything can always be compromised. Salt/hashing can prove beneficial, for instance, in the event your database is compromised but not your file system. SQL Injection, which is a very common type of attack, could serve your database to an attacker, but without the attacker knowing the hardcoded salt string, attempting to build a rainbow table, let alone match against one, becomes almost impossible. Thus, you and your user’s passwords, theoretically, cannot be discovered. (If the file system is also compromised, a rainbow table could technically be built. Strong passwords are always recommended! This demonstration is not a replacement for strong passwords.)
Why does this matter? For you, it may not. If you are “password conscience” then you may already use separate passwords for almost every website and email account. Unfortunately, the majority of users do not. They are generally using a weak password, not only for your website, but most likely for the email account they are registered with. Securing passwords helps to ensure that your customers private information stays private.
With TomatoCMS (version 2.0.8), adding salt/hashing to the authentication system requires only a few modifications, to the database as well as a few files. If this is not a new installation of TomatoCMS, all users will be required to reset their passwords using the forgot password option, after the modifications are made. Verify that the user email addresses are all correct, and that the mail system is working correctly. This demonstration assumes you have a general overall knowledge of PHP, TomatoCMS, and your database of choice (TomatoCMS’s database).
Read the following entirely before you begin
The first step, in your database, find the core_users table and add a column `salt` varchar(50) after the password column.
Next, in your bootstrap file, add the following method.
/application/Bootstrap.php
/** ... **/
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
/** ... **/
protected function initStaticPasswordSalt()
{
if (!defined('STATIC_APP_SALT')) {
define('STATIC_APP_SALT', md5('TH1S STR1NG SH0ULD N3V3R B3 MOD1F13D'));
}
}
Now, you will need to make a quick modification to
/application/modules/core/services/Auth.php
Remove the md5() function call from the first line of the authenticate method, as follows.
/** ... **/
public function authenticate()
{
//$password = md5($this->_password);
$password = $this->_password;
/** ... **/
}
/** ... **/
Don’t worry, we will handle all our hashing in the user dao (where most of the hashing is performed originally). So, now we need to edit the dao. This should be done for all available daos, but technically you only need to edit whichever one you are using.
The following demonstrates using the pdo_mysql extension, so you may need to modify it if you are using another extension. Edit the file
/application/modules/code/models/dao/pdo/mysql/User.php
You will want to edit the second where statement in the authenticate method (this is where we replace the hash we removed in the last step).
/** ... **/
class Core_Models_Dao_Pdo_Mysql_User extends Tomato_Model_Dao
implements Core_Models_Interface_User
{
/** ... **/
public function authenticate($username, $password)
{
$select = $this->_conn
->select()
->from(array('u' => $this->_prefix . 'core_user'))
->joinLeft(array('r' => $this->_prefix . 'core_role'), 'u.role_id = r.role_id', array('role_name' => 'name'))
->where('u.user_name = ?', $username)
->where('u.password = SHA1(CONCAT(?,u.salt))', sha1($password . STATIC_APP_SALT))
->limit(1);
$row = $select->query()->fetch();
return (null == $row) ? null : new Core_Models_User($row);
}
/** ... **/
What this does is hash the password with our static (hardcoded) salt, then lets the database hash it again with the stored salt. The stored salt will be generated anytime a new password is created, so we need to add a quick method for creating a salt, as follows.
/** ... **/
protected function getSalt()
{
return md5(time() . rand(1,999));
}
/** ... **/
Almost there. Now, we need to edit the following methods that will be updating the passwords.
/** ... **/
public function update($user)
{
$where[] = 'user_id = ' . $this->_conn->quote($user->user_id);
$data = array(
'user_name' => $user->user_name,
'full_name' => $user->full_name,
'email' => $user->email,
'role_id' => $user->role_id,
);
if (null != $user->password && $user->password != '') {
$salt = $this->getStalt();
$data['password'] = sha1(sha1($user->password . STATIC_APP_SALT) . $salt);
$data['salt'] = $salt;
}
return $this->_conn->update($this->_prefix . 'core_user', $data, $where);
}
public function updatePassword($user)
{
$salt = $this->getSalt();
$where[] = 'user_id = ' . $this->_conn->quote($user->user_id);
return $this->_conn->update($this->_prefix . 'core_user', array(
'password' => sha1(sha1($user->password . STATIC_APP_SALT) . $salt),
'salt' => $salt,
), $where);
}
public function updatePasswordFor($username, $password)
{
$salt = $this->getSalt();
$where[] = 'user_name = ' . $this->_conn->quote($username);
return $this->_conn->update($this->_prefix . 'core_user', array(
'password' => sha1(sha1($password . STATIC_APP_SALT) . $salt),
'salt' => $salt,
), $where);
}
/** ... **/
That’s it! Now go reset your password.
I will try to add to this soon, but it’s all the time I have for now… Enjoy!
Comments are closed.