CakePHP2でパスワードハッシュのソルト付与、ストレッチング

はじめに

昨日触れましたが、先日パスワードをハッシュで保存する場合

  • ソルトを付ける
  • ストレッチングする

必要があることを教わりました。

その必要があることは知っていましたが具体的にどのように実装するのかやったことがなかったので試してみました。

対策する理由

  • なぜソルトをつけるのか

パスワードを長くしてレインボーテーブルをつかった攻撃に対応するため

  • なぜユーザごとに異なるソルトにするのか

同じパスワードでもユーザが違えば違うハッシュにしたいから

  • なぜストレッチングするのか

総当たり攻撃に時間がかかるようにするため

試した環境

OS:CentOS6.5 64bit
Web:Apache 2.2 + PHP5.5
DB:PostgreSQL 9.3

CakePHPでよくあるUsersテーブルで認証する仕組みは構築済み

やり方

CakePHPでの認証処理はAuthComponentというコンポーネントが用意されていますが、こいつそのままではソルトは固定値でストレッチングしません。
これをユーザーごとにソルトを変更し、ストレッチングするようにしてみます。
PHP5.5で導入されたpassword_hash関数を使うPasswordHasherクラスを作成し使うようにします。

  • /Controller/Component/Auth/SlowPasswordHasher.php
<?php

App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');

class SlowPasswordHasher extends AbstractPasswordHasher {

    public function hash($password) {
        //password_hashの戻り値にはcost(ストレッチ回数)とソルトを含むよ
        //costの13は2^13回のストレッチング
        //optionでsaltを与えなければ自動生成
        return password_hash($password, PASSWORD_BCRYPT, ['cost' => 13]);
    }

    public function check($password, $hashedPassword) {
        return password_verify($password, $hashedPassword);
    }

}
  • /Controller/AppController.phpとかの$components
    public $components = array(
        'Auth' => array(
            'authenticate' => array(
                'Form' => array(
                    'passwordHasher' => 'Slow'
                )
            )
        )
    );
  • /Model/User.php
<?php

App::uses('AppModel', 'Model');
App::uses('SlowPasswordHasher', 'Controller/Component/Auth');

class User extends AppModel {

    public function beforeSave($options = array()) {
        if (isset($this->data[$this->alias]['password'])) {
            $passwordHasher = new SlowPasswordHasher();
            $this->data[$this->alias]['password'] = $passwordHasher->hash($this->data[$this->alias]['password']);
        }
        return true;
    }

}

まとめ

PHP5.5のpassword_hash関数を使うと
簡単にパスワードハッシュのユーザごとに異なるソルト付与とストレッチングできました。