こないだ、よくわからんので今度調べると書いたところについて。
CSRFの対応について、rails使いが知っておくべきこと - おもしろWEBサービス開発日記
まずクッキーとセッションの違いから。自分の認識はこんな感じ
- クッキーもセッションも、ブラウザにデータを保存させる仕組み。
- クッキーはデータをそのままブラウザに保存させる。
- セッションはセッションIDをブラウザに保存させ、データはサーバ側が保持する。サーバはセッションIDをキーにしてデータを取り出す。
railsでクッキーを設定するには
railsでは、クッキーは基本的に使わないと思ってますが、一応使い方をメモ。
cookies[:hoge] = { :value => "value", :expires => "30.days.from_now", :path => "/store", :domain => "www.example.com", :secure => true }
- value
- ブラウザに保存する文字列。文字列のみが格納できる。
- expiers
- クッキーの有効期限。設定をしないと、クッキーをメモリ上で管理しブラウザセッション*1が終了すると削除される。
- path
- ブラウザがクッキーを送信するパスを設定する
- domain
- ブラウザがクッキーを送信するドメインを設定する
- secure
- httpsの時だけクッキーを送信するように設定する
(追記)
- httponly
- trueにすると、IEとFireFoxではJavaScriptでcookieを取得できなくなる
セッション関連でのrailsの設定と動作について
config/environment.rbにはデフォルトで下記のような設定がされています。
config.action_controller.session = { :session_key => '_hoge_session', :secret => '9c295a9323d9c6f29c872f0f8ac5632911e69a78a8dd9a5fd748d3aa8ec5523db2f1ad0e73f03e71a5162c593d510f85111cd995b36193e3322975e276d5644d' }
まず、railsはセッション格納時に、上記の:session_keyで設定された文字列をキーにして値を格納します。値は、セッションの格納方法によって異なるデータが格納されます。セッションの格納方法は大別してクッキーセッションとそれ以外(ファイル、メモリ、DB)に分けられます。
クッキーセッションの場合
こちらはrailsデフォルトのセッション格納方法です(2.0以降)。値には、格納したいデータをマーシャルしたものと認証用のデータをハイフンでつないで入れます。認証用のデータは、マーシャルしたデータと:secretに設定された値を使って暗号化します。
クッキーセッションを使った際の注意点としては、
- クッキーなので4K以上のデータが入らない
- データ自体は暗号化されないので、ユーザに見せたくないデータを格納しちゃだめ
などがあります。
クッキーセッション以外の場合
値には、ランダムに作成した32桁の16進数を入れます(セッションID)。格納したいデータは、セッションIDをキーにしてサーバに格納します。
protect_from_forgeryのsecretの意味について
(追記)Rails2.3からは:secretオプションはdeprecatedになっていて、指定しても効果がないようです
以前こんなことを書きました。
protect_from_forgery # :secret => '8ff3ed33f86a431662d8dfe255acdb4a'
上記のコードに書いてある:secretというオプションは、セッションをDBまたはメモリに格納しているときにだけ使います。
CSRFの対応について、rails使いが知っておくべきこと - おもしろWEBサービス開発日記
セッションをDBまたはメモリに格納しているときだけ:secretを使うのはなぜかよくわからなかったので、調べてみました。
まず、クッキーセッション以外の場合は、CSRFのチェック方法として「session[:csrf_id]に格納されているセッションIDとsecretを使って生成した値」とauthenciticy_tokenと比較をおこなっているようです。クッキーセッション以外の場合は、なぜかセッションIDを使ってDBやメモリからデータを取得したりはしてないみたい*2なので、認証用のキーとして:secretを使っているみたいです。
普通にセッションIDを使って、サーバ側に格納したデータを取得してauthenciticy_tokenと比較すればいいような気がしますが・・・パフォーマンスの問題なのかな?
railsでのセッション格納方法
クッキー以外の格納方法を調べてみました。
PStore
PStoreでマーシャライズしてファイルに格納する方法。1.2まではrailsのデフォルトだったようです。
こんな感じで設定します。
Rails::Initializer.run do |config| config.action_controller.session_store = CGI::Session::PStore config.action_controller.session_options[:tmpdir] = "/Users/hoge" config.action_controller.session_options[:prefix] = "myapp_session_" end
ActiveRecord
データベースにセッションデータを格納する方法。
Rails::Initializer.run do |config| config.action_controller.session_store = :active_record_store end
下記rakeコマンドで、sessionsテーブルを作成するマイグレーションを作成できます。
rake db:sessions:create
Drb
DRbサーバにセッションデータを格納します。ちなみにDRbとは、Rubyプロセスがネットワーク接続を経由してオブジェクトを共有できるようにするプロトコルのこと。
Rails::Initializer.run do |config| config.action_controller.session_store = :drb_store end
MemCache
memchachedでセッションを格納する方法。
Rails::Initializer.run do |config| config.action_controller.session_store = :mem_cache_store end
Memory
メモリ内に格納する。一般的に望ましくない方式らしい。
Rails::Initializer.run do |config| config.action_controller.session_store = :memory_store end
Database
フラットファイルに格納する。セッションの内容が文字列でなければならないのであんまり使われないらしい。
セッションのオンオフ
(追記)Rails2.3から、sessionは遅延ローディングされる(必要なときだけ呼び出されて使われる)ようになったため、下記のようにoffとか指定する必要がなくなりました。たぶん指定しても無視されるはず。
セッションストレージは、アプリケーション全体に対してや、コントローラやアクションごとに有効/無効を切り替えたりできるらしい。
下記のようにすると、HogeControllerでセッションストレージをオフにできる。
class HogeController < ActionController::Base session :off # ... end
また、before_filterなどと同じように:only, :except, :ifも使える。