[Rails] Rails 3.0.4, 2.3.11 におけるセキュリティー対応について

本日、Rails2.3.11がリリースされましたね。Rails3.0.4と同時に。主にセキュリティーの対応のようです。
http://weblog.rubyonrails.org/2011/2/8/new-releases-2-3-11-and-3-0-4

主な内容はこちらのようです。

  1. 2.x.x, 3.0.x 系両方に影響あり
    1. mail_to の :encode=>:javascript オプションにXSSの可能性あり (CVE-2011-0446)
    2. CSRF を通り抜けられる可能性あり (CVE-2011-0447)
  2. 3.0.x 系だけに影響あり
    1. Filter Problems on Case Insensitive Filesystems (CVE-2011-0449)
    2. limit()にSQLインジェクションの可能性あり (CVE-2011-0448)

僕が対応の際に調査した項目などをまとめておきます。まず対応したのがRails2系でした。mail_toのオプションに関してXSSがある問題は、利用していないので影響はありませんでした。このオプションはあまり利用されていない気がするので、影響を受ける人はあまりいないかもしれません。

一番影響のある変更は、CSRFの問題ではないでしょうか?以下がCSRFの問題に対する公式なメーリングリストの投稿とGithubのコミットログです。

このブログでは主にここを中心に解説します。

もともとRailsでは、CSRFの対応にトークンを用いて防いでいます。その際にAjaxのXHRリクエストでは、CSRFが起こりえないという前提でトークンでの検証を行わないというコードになっていました。本来はそうなのですが、コミットログなどを参考にすると FlashJava applets を利用した場合に起こる可能性があるようなのです。今回のRailsの対応は、XHRリクエストの際もトークンで検証を行うというような変更が行われています。この変更がコミットログの以下の部分です。
https://github.com/rails/rails/commit/7e86f9b4d2b7dfa974c10ae7e6d8ef90f3d77f06#L0R88

この変更ため、Ajaxの処理の際にもトークンを送る必要がでてきました。新しく追加された csrf_meta_tag をlayoutなどで全てのページで定義して、jQueryの場合は以下のようにしてトークンを常にヘッダーに加えるようです。
https://gist.github.com/818083
csrf_meta_tag の追加部分はコミットのここあたりです。
https://github.com/rails/rails/commit/7e86f9b4d2b7dfa974c10ae7e6d8ef90f3d77f06#L2L-1

さらに、今回の変更でこれまでCSRFトークンの検証が正しく行われなかった場合にはエラーをraiseしてエラー画面を表示するという処理が行なわれていましたがこの部分も変更されました。エラー画面を表示するのではなく、ログアウト処理を行う様になっています。この理由は、まだ僕は分かっていないのです。誰か教えて!!この変更はコミットログのこの部分です。
https://github.com/rails/rails/commit/7e86f9b4d2b7dfa974c10ae7e6d8ef90f3d77f06#L0R75

この変更では、ログアウト処理は reset_session が呼ばれるだけになっています。もし、「ログイン状態を保存機能」などで reset_session だけではログアウトされない場合は、 handle_unverified_request メソッドをアプリケーションで上書きしてcookieを削除するように変更してくださいっとメーリングリストに書いているのでご注意ください。

まとめ

今回のアップデートの中のCSRFのリスクに必要な手順は以下となりそうです。
1. Railsのバージョンアップ (一時的なパッチで対応するようのパッチも作りました https://gist.github.com/818088 このファイルを config/initializers 以下に置く)
2. jQueryなどでトークンを送信しないAjaxリクエストを用いている場合は、 csrf_meta_tag をviewに組み込み、サンプルを参考にヘッダーでトークンを送信するようにする
3. ログアウト処理が reset_session だけで完了しない場合は、 handle_unverified_request を実装する

急いで調査・まとめを行ったため間違いがあるかもしれませんので、その際はご指摘いただければ幸いです。また、反映する際はご自身でご確認の上ご利用ください。