読者です 読者をやめる 読者になる 読者になる

おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

railsのクッキーとセッションについてまとめ

こないだ、よくわからんので今度調べると書いたところについて。

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にすると、IEFireFoxではJavaScriptcookieを取得できなくなる

railsでセッションを設定するには

これは常識かな。

session[:hoge] = "hoge"

セッション関連での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も使える。

*1:ブラウザが終了するまで保持されるセッションのことみたい

*2:あまりきちんと調べていません。ほんとか?と思った方はご自分で調べてみてください。