RailsのSession管理について
RailsでSessionの管理を行う際に、SessionStoreという形式が提供されています。
ファイルでいうところの config/initializer/session_store.rb
です。
デフォルトではCookieStoreというブラウザのCookieを使う方法が利用されています。
CookieStoreは、サーバを通ることがないため非常に高速ですが、いくつのか欠点もあります。
- 逆にサーバからSession情報を変更したいタイミングでアクセスができない。
- CookieSessionへの再生攻撃やセッションハイジャックなどのセキュリティリスク
他にもありますが、プロトタイプを作る際などには他のサーバやmiddlewareを用意する必要もありませんが、サービスが伸びてくるにつれ、上記の欠点が浮き彫りになってくると思います。
ActiveRecord-Session_Storeについて
これはActiveRecordでSessionを管理する方法です。すなわちブラウザCookieではなく、DBでsessionを管理します。
gemとして提供されており、READMEのInstallationを行うだけでよく、非常に楽です。
他にもSessionStoreとしてはredis-railsが有名でしょうか。
Sessionのloadとdump
ActiveRecord-Session_Storeでは、serializerというどういった形式でsessionを保存するのかが記載されています。
- MarshalSerializer
- Marshalモジュールにて書き出し、読み込みを行いBase64で加工をしています。
- JsonSerializer
- 名の通り、JSON形式で管理をします。
- HybridSerializer
- Marshal形式からJson形式への変更を行うhybridな管理法です。
- NullSerializer
- データを何も加工せず、そのまま保存する形式です。
Rails version更新時に伴うactiverecord-session-storeの振る舞いについて
ここでようやくタイトル回収です。
Railsのversionを更新する際には、ActiveSupportにて定義されているMarshal#load
の形式も変わります。
- 4.2系の場合
- 5.1系の場合
version upの際に、SessionデータをMarshal形式で保存していると、
例として4.2から5系へと更新をするとして
更新タイミングでMarhsalの形式が変更され、sessionを読み込むのと同時に値が変わる可能性があります。
何もなければ問題はありませんが、一部のデータではempty hashの値がnilになっていたりと、version更新時に障害となる可能性があります。
対策
対策としては簡単で、Session情報を削除するだけです。
そうすることで、Railsの新規versionで新しくSessionデータが作られるので、versionの変更によるデータ不整合は起きません。
$ bin/rake db:sessions:clear
とすることで、sessionsテーブルがtruncateされ、sessionデータを空にすることができます。
とはいえ本当に空にしていいのかはアプリケーションの実装にもよると思います (immutableではないなど)
その場合は、Railsのversion更新前にHybridSerializer
を利用し、Marshal形式からJSON形式へ変更をしておくと安心できるかもしれません。