Home > PHP > CakePHP Authコンポーネントでパスワード・ハッシュをストレッチングするには?

CakePHP Authコンポーネントでパスワード・ハッシュをストレッチングするには?

  • 2011-05-27 (金) 13:08
  • PHP

体系的に学ぶ 安全なWebアプリケーションの作り方 』で解説されていたパスワード・ハッシュのストレッチングをCakePHPで実装してみました。 
ストレッチング処理の肝となる部分は書籍に書いてある内容のままですので(汗)、設定方法を簡単に説明します。

【 注意事項 】
今回実装したStretchAuthコンポーネントの導入にはパスワード( ハッシュ )の再登録が必要です。
また、運用中のシステムへの導入や導入後の設定変更により、ハッシュ方式やストレッチ回数が異なるパスワードがDBへ登録されますので、必ずDB及びシステムのバックアップを行ってからお試しください。

体系的に学ぶ 安全なWebアプリケーションの作り方

※ 諸般の事情により、CakePHP-1.2.10 でしか動作確認していませんので 1.3 や 2.0 で動いた方は @scriptwork まで教えて頂けると助かります

それではまず bootstrap.php でパラメーターを設定。

define( 'HASH_TYPE',     'sha256' ); // 使用するハッシュ関数の種類
define( 'STRETCH_COUNT', 1000 );     // ハッシュのストレッチング回数

HASH_TYPE は 使用するハッシュ関数のアルゴリズムでPHPのhash関数へのパラメーターになります。
sha1 / sha256 / sha512 など、お使いのサーバー環境に合わせて指定してください。
※ CakePHP 1.3.9 と 2.0-alpha はデフォルトが sha1 になっていますが、できれば sha256 か sha512 がお薦め

HASH_TYPEの指定によって、生成されるハッシュ値の長さが変わります。
このため、mysql側もパスワードハッシュを格納するフィールドサイズの調整が必要。
※ 実際にPHP 5.3.6で生成されたハッシュの長さを見るとsha256で64バイト、sha512なら128バイトでした

STRETCH_COUNT でパスワード文字列に対するハッシュ関数の適用回数を指定。
ここはサーバー性能とアクセス負荷のバランスによって調整が必要なところですが、とりあえず1000回で様子見中…


次に今回実装した StretchAuthコンポーネント を使うため app_controller.php で
$components への登録(1行目) と 既にAuthコンポーネント を使っている場合を考慮して beforeFilter() で
デフォルトのハッシュアルゴリズムの指定(5行目) と $this->Auth に StretchAuth かぶせます(6行目)


次に今回実装した StretchAuthコンポーネント を使うため app_controller.php で $components に登録します。
# 以前、beforeFilterで行っていた初期化処理は @nojimage さんのアドバイスで stretch_auth.php の initialize() へ収容しました。( 情報感謝 )

var $components = array( 'StretchAuth' );

StretchAuthコンポーネント( ↓stretch_auth.php )を app/controllers/components へ配置。

コントローラーから使うときの変更点は passwordメソッド(33行目)で新たにユーザー固有のソルトを使用するため、引数に $username を追加しています。 また passwordメソッド の変更に合わせて、hashPasswordsメソッド 側も passwordメソッド を呼び出すときの引数に username を追加(23-24行目)。

40-42行目がストレッチング処理 powerd by WASBOOK!

<?php
App::import( 'Component', 'Auth' );

// Authコンポーネントの拡張
class StretchAuthComponent extends AuthComponent {

    // コンポーネント初期化
    function initialize( &$controller ){
        $controller->Auth =& $this;     // コントローラー側の $this->Auth をオーバーライド
        Security::setHash( HASH_TYPE ); // デフォルトのハッシュアルゴリズムを設定

        parent::initialize( $controller );
    }

    // ログインフォームからの username と password でハッシュ生成
    function hashPasswords($data) {
        if (is_object($this->authenticate) && method_exists($this->authenticate, 'hashPasswords')) {
            return $this->authenticate->hashPasswords($data);
        }

        if (is_array($data) && isset($data[$this->userModel])) {
            if (isset($data[$this->userModel][$this->fields['username']]) && isset($data[$this->userModel][$this->fields['password']])) {
                $data[$this->userModel][$this->fields['password']] = $this->password($data[$this->userModel][$this->fields['password']],
                                                                                     $data[$this->userModel][$this->fields['username']]
                    );
            }
        }
        return $data;
    }


    // パスワード・ハッシュ生成( ストレッチング対応版 )
    function password( $password, $username = null ) {

        // ユーザーごとの固有ソルトを設定
        $salt = $username . pack( 'H*', Configure::read('Security.salt') );

        // パスワード・ハッシュのストレッチング処理
        $hash = '';
        for( $i = 0 ; STRETCH_COUNT > $i ; $i++  ){
            $hash = hash( HASH_TYPE, $hash . $password . $salt );
        }

        return $hash;
    }

} // End class
?>
$password_hash = $this->Auth->password( $raw_password, $username );

以上、コントローラーから使うときは第2引数の $username を忘れずに!

今回、参考にした 体系的に学ぶ 安全なWebアプリケーションの作り方 という本はこちらです。

今後は?

WASBOOK著者の 徳丸さん からアドバイス頂き、運用中の ハッシュ方式 と ストレッチング回数 そして ソルト の変更に対応する機能を実装します。

構想としては 障害切り分け や 切り戻し を考慮して、Usersテーブルとは別にPasswordsテーブルを用意してパスワード、ハッシュ方式、ソルトのタイプ、ストレッチ回数を持たせる予定です

Home > PHP > CakePHP Authコンポーネントでパスワード・ハッシュをストレッチングするには?

Fedora 20
アーカイブ

Return to page top