Padrinoのsessionをredisに保存しようとした

# 背景
- Padrinoでログイン情報などを保持するのにsessionを使っています。
- 通常は ```config/apps.rb``` か ```app/app.rb``` で ```enable :sessions```
と記述してsessionを有効にしますが、この方法だとsessionの内容は全てcookieに入ってしまいます。
その気になれば簡単に ```Marshal.load``` で内容を見ることができます。
    - 参照: http://d.hatena.ne.jp/riocampos+tech/20140616/private_study_about_rack_session_or_cookie
- cookieにはsession idのみ格納し、内容はサーバサイドに保存する方が安全だろうし、通信量も少し減るかな、と思って方法を探りました。

# 試したもの
- 少し昔の記事ですが、これを参考にしてテストしてみました。
    - http://takaaki-kasai-tech.blogspot.com/2014/05/how-to-use-rack-session-pool-on-padrino.html
        - これは ```Rack::Session::Pool``` を使う例。このmiddlewareは
        ```@pool``` にsessionの内容を保存し、cookieにはsession idのみ格納します。
        - 特にサーバサイドで設定が不要なのが手軽な感じです。
        - アプリケーションを終了すると内容が消失します。
    - http://takaaki-kasai-tech.blogspot.com/2014/05/session-management-by-rack-session-redis.html
        - これは ```Rack::Session::Redis``` を使う例。このmiddlewareは
        key-valueストアであるredisにsessionの内容を保存し、cookieにはsession idのみ格納します。
        - サーバサイドでredisを動かす必要があります。開発機でも動かす必要があります。
        - アプリケーションを終了しても内容が残ります。

# コード
- app/app.rbに以下の記述を行ないました。

    ```ruby
        set :protection, false
        set :protect_from_csrf, false
        disable :sessions
        use Rack::Session::Redis, path: '/', domain: nil, expire_after: 86400
        use Rack::Protection
        use Rack::Protection::AuthenticityToken
    ```

# 難点
- どちらのmiddlewareを使っても、POSTメソッドでアクセスするとforbiddenと言われてしまいました。サーバでは

    ```
    attack prevented by Rack::Protection::AuthenticityToken
    ```
というメッセージが出ます。

- ```Rack::Protection::AuthenticityToken``` を使用すると、CSRFチェックが行なわれます。```set :protect_from_csrf, true``` しているのと同様ですが、後者の場合はpadrinoのform helperが自動的にCSRFチェック用のトークンを送るinputタグを作ってくれます。

    ```html
    <form action="/a" accept-charset="UTF-8" method="post">
    <input type="hidden" name="authenticity_token" value="何らかのトークン" />
    <input id='key' name='key' type='text'>
    ...
    ```
- この動きは、```padrino-helpers``` の ```form_helpers.rb``` の中の ```Padrino::Helpers::FormHelpers#formtag``` で以下のように記述されています。

    ```ruby
      def form_tag(url, options={}, &block)
        options = {
          :action => escape_link(url),
          :protect_from_csrf => is_protected_from_csrf?,
          'accept-charset' => 'UTF-8'
        }.update(options)
        options[:enctype] = 'multipart/form-data' if options.delete(:multipart)

        if (desired_method = options[:method]) =~ /get/i
          options.delete(:protect_from_csrf)
        else
          options[:method] = 'post'
        end
        inner_form_html = hidden_form_method_field(desired_method)
        inner_form_html << csrf_token_field if options.delete(:protect_from_csrf)
        concat_content content_tag(:form, inner_form_html << capture_html(&block), options)
      end
    ```

    - オプション ```protect_from_csrf``` が ```true``` なら ```csrf_token_field``` が
    生成されます。デフォルト値として ```is_protected_from_csrf?``` の返り値が指定されていて、
    このメソッドは ```settings.protected_from_csrf``` を見ています。従って ```set :protect_from_csrf, true```
    しないとこれは ```true``` になりません。
    - ところが、これを行なうと、padrinoアプリケーション起動時に ```padrino-core/application/application_setup.rb``` で
sessionが有効かをチェックするので、

        ```you need to set up a session middleware *before* Rack::Protection::AuthenticityToken (RuntimeError)```

    というエラーになります。

# 解決
- 理論的には全てのフォームの作成時にpadrinoのヘルパで

    ```form_tag(url(:a, :index), method: :post, protect_from_csrf: true) do```

とすればいいのですが如何にも面倒臭いし、書き忘れてエラーを出しそうな感じです。

- 結局解決しなかったのですが、以下のような力技もあります。
    - こんなモンキーパッチを書いて、helperとして読み込ませます。

        ```ruby
        module Padrino::Helpers::FormHelpers::Security
          def is_protected_from_csrf?
            MyProject::App.middleware.map(&:first).include?(Rack::Protection::AuthenticityToken)
          end
        end
        ```
# 結論
- スマートなやり方はないものでしょうか。
- ```Padrino::IGNORE_CSRF_SETUP_WARNING=true``` と ```set :protect_from_csrf, true``` を併用するのがよいのかな?