symfonyでsession_regenerate_id()

session_regenerate_id()を使うとセッションIDを簡単に変更できるので、少なからずセッションハイジャック対策ができる。

symfonyで認証画面を作り、ログイン時にsession_regenerate_idしてIDを再発行しようと思ったけど、デフォルトのsfSessionStorageを使うとID変更前に処理が終わってしまい画面遷移したあとに変更後のIDでセッションが利用できない。

なので、とりあえず自前でmySessionStorageクラスを用意して回避することにした。

project/lib/storage/mySessionStorage.class.php

<?php
class mySessionStorage extends sfMySQLSessionStorage // ※ウチの環境ではsfMySQLSessionStorage使ってるので
{
  public function initialize($context, $parameters = null)
  {
    parent::initialize($context, $parameters);
  }
  
  public function regenerateID ()
  {
    $old_session_id = session_id();
    session_regenerate_id(); 
    $new_session_id = session_id();

    //destroy the old session ID
    session_id($old_session_id);
    session_destroy();

    //need to re-register all user-level handlers again (should they exist)
    @session_set_save_handler(array($this, 'sessionOpen'),
                              array($this, 'sessionClose'),
                              array($this, 'sessionRead'),
                              array($this, 'sessionWrite'),
                              array($this, 'sessionDestroy'),
                              array($this, 'sessionGC'));

    //starts the new session ID again
    session_id($new_session_id);    
    session_start();
  }
}

app/config/factories.yml

all:
  storage:
    class:  mySessionStorage
    param:
      db_table:                session
      db_id_col:               id
      db_data_col:             data
      db_time_col:             updated_at
      database:                propel
      session_cookie_domain:   .example.com // 実際はプロジェクトのドメイン名


あとは任意のコントローラ側でmySessionStorageのregenerateIDを呼ぶ。

<?php

    pubic function executeLogin()
    {
      // 省略
      $this->getContext()->getStorage()->regenerateID();
      // 以下ログイン処理
    }

これで一応上手くいく。ていうか公式で対応してほしいんだが。