Nucleus

Cookie key を暗号化

2007年3月28日

 Nucleus では、ログインキーは md5 で暗号化されて MySQL データベースに保存されているが、クッキー認証キーは生のまま保存されている。これだと、万一、何かしらの脆弱性(SQL injection など)でクッキー認証キーが洩れた場合に、セッションハイジャックが起きる。
 md5 で暗号化すれば、万一クッキー認証キーが洩れても、暗号解読が必要なので、セッションハイジャックは難しい。ついでに、md5 による暗号化の前に$_SERVER['REMOTE_ADDR']の情報も加えておけば、XSS でクッキー認証キーが洩れても、別のIP address からの接続はほとんど不可能である。
 先日、MEMBER.php の改造でこれを実現しようとしたのであるが、なかなか改造コードが完成しなかった。改めてコアのコードを見てみると、globalfunctions.php の改変だと、比較的簡単にこれが実現できることが分かった。

globalfunctions.php 180行目付近
    if ($member->login($login, $pw) ) {

        $member->newCookieKey();
        $member->setCookies($shared);

        $member->setCookieKey(md5($member->getCookieKey().serverVar('REMOTE_ADDR'));
        $member->write();


235 行目付近
} elseif (cookieVar($CONF['CookiePrefix'] . 'user') ) {
    // Cookie Authentication
        $res = $member->cookielogin(cookieVar($CONF['CookiePrefix'] . 'user'), md5(cookieVar($CONF['CookiePrefix'] . 'loginkey').serverVar('REMOTE_ADDR')) );

    // renew cookies when not on a shared computer
    if ($res && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) && (!headers_sent() ) ) {
        $member->setCookieKey(cookieVar($CONF['CookiePrefix'] . 'loginkey'));
        $member->setCookies();
    }

これで、クッキー認証キーが、接続元の IP アドレス付きで暗号化されて MySQL データベースに格納される。

これをプラグインにしようとすると少し厄介で、やはり、コアの書き換えが必要になる。

<?php
class NP_SecureCookieKey extends NucleusPlugin { 
    function getName() { return 'NP_SecureCookieKey'; }
    function getMinNucleusVersion() { return 220; }
    function getAuthor()  { return 'Katsumi'; }
    function getVersion() { return '0.1'; }
    function getURL() {return 'http://hp.vector.co.jp/authors/VA016157/';}
    function supportsFeature($what) { return (int)($what=='SqlTablePrefix'); }
    function getEventList() { return array('PreAuthentication','LoginSuccess','PostAuthentication'); }
    var $disabled=true;
    var $LoginSuccess=false;
    function getDescription() {
        return $this->getName().' plugin. ' . ($this->disabled ?
            'This plugin is now disabled. Please edit globalfunctions.php and add '.
            '"$manager->notify (\'PreAuthentication\',array());" just before the '.
            '"$member =& new MEMBER();".':'');
    }
    function event_PreAuthentication(){
        global $CONF,$HTTP_COOKIE_VARS;
        $this->disabled=false;
        if (cookieVar($CONF['CookiePrefix'] . 'loginkey')) {
            $CONF['NP_SecureCookieKey']=cookieVar($CONF['CookiePrefix'] . 'loginkey');
            $HTTP_COOKIE_VARS[$CONF['CookiePrefix'] . 'loginkey'] =
            $_COOKIE[$CONF['CookiePrefix'] . 'loginkey'] =
                md5($CONF['NP_SecureCookieKey'] . $_SERVER['REMOTE_ADDR']);
        }
    }
    function event_LoginSuccess(&$data){
        if ($this->disabled) return;
        $member=&$data['member'];
        $member->setCookieKey(md5($member->getCookieKey().$_SERVER['REMOTE_ADDR']));
        $member->write();
        $this->LoginSuccess=true;
    }
    function event_PostAuthentication(&$data){
        global $member,$CONF;
        if ($this->disabled || $this->LoginSuccess) return;
        if (!$data['loggedIn']) return;
        if (!cookieVar($CONF['CookiePrefix'] . 'user')) return;
        if (cookieVar($CONF['CookiePrefix'] . 'sharedpc')) return;
        if (headers_sent()) return;
        $member->setCookieKey($CONF['NP_SecureCookieKey']);
        $member->setCookies();
    }
}
?>

この場合は、globalfunctions.php の『$member =& new MEMBER();』の前に、

$manager->notify ('PreAuthentication',array());

を書き加える必要がある。同様のコードを config.php に持ってくることも可能だが(その場合は、コアの書き換えは要らない)、その場合はクッキープレフィックスにうまく対応できない。

追記:
この機能は、Nucleus 3.3 に採用される予定です。

コメント

コメントはありません

コメント送信