トップ 最新 追記   RSS 1.0 FEED  

Journal InTime


2008-01-13 (Sun) [長年日記]

_ [Rails] CookieStoreとセキュリティ

Rails 2.0ではCookieStoreという新しいセッションストアが導入されている。 CookieStoreは、セッションデータをサーバ上のファイルやDBに保存する代りに、クッキー自体に保存する。 このため、セッションデータの読み書きのコストが減ったり、古いセッションデータ の掃除の手間がなくなる、という利点がある。

「そんなことをしたらユーザにセッションデータを改竄されるじゃないか」というのが 当然の疑問だが、HMAC(デフォルトではSHA1)によるチェックで改竄を防ぐようになっ ている。

ただし、セッションデータ自体は平文(marshal+base64)なので、中身を見られてしま う。これについては、そもそもユーザに見られては困るようなデータをセッションデ ータに格納すべきではない、という立場を取っているようだ。

ちょっと気になるのが、サーバが一度発行したクッキーは、HMACで使用する鍵を 変えたりしない限り、ずっと有効だということだ。 悪意のある第三者がクッキーを盗聴してリプレイを試みる、というケースに ついては、盗聴できたという時点で他のセッションストアの場合もセッションハイ ジャックが可能になるので、CookieStoreがとりわけ危険だというわけではない。 気になるのは、ユーザがセッションの状態を任意の時点に戻すことができる点だ。 アプリケーションの作りによっては悪さができそうな気もするのだけれど、 実際のところどうなのだろう。 「そんなことができるアプリケーションはそもそも作りが悪いのだ」と言ってすませ ることができるものなのだろうか。

たとえば、セッションデータにはユーザIDだけ格納しておいてその他の状態は全部DBに格納すれば 上記のような心配はしなくていいわけだけど、それだったら最初からActiveRecordStore を使えばいい気もする。

任意の時点にセッションの状態を戻されること自体を防ぐには、セッショ ンデータにnonceを入れておいてチェックすればよい。 ただ、サーバ側でnonce値を保存する必要があるということになるとCookieStoreの利点(高速・セッションデータの掃除が不要)がかなり損なわれる。

というわけで、簡単な解決は思い付かなかった。そもそも問題なのかどうかもよくわかっていないのだが。

最後にもう一点。CookieStoreの場合、session fixation attackの心配がなくなりそうだ。 攻撃者が被害者に特定のセッションIDを利用するように仕向けることができない(と いうかそもそもセッションID自体がない)から(見落としがあればご指摘を)。

「あれ、session fixation attackってRails 1.2.4と1.2.6で対策されたんじゃないの?」 と思われるかもしれないが、Rails 1.2.4/1.2.6ではURLでセッションID を指定できないようにしただけなので、Cookie MonsterやXSSを利用した攻撃を考え るとアプリケーション側で対策が必要だ。 認証の際にreset_sessionでセッションIDを変更すればよいのだが、自分の知るかぎり どの認証プラグインも対策してないので自分で対策する必要がある。

_ [Rails] RailsによるアジャイルWebアプリーション開発第2版とRails 2.0

Rails 2.0で…という質問が今後増えることが予想されるわけですが、 とりあえず、

> gem install -v 1.2.6 rails

としてRails 1.2.6をインストールして一通りチュートリアルをこなした上で、Rails 2.0に移行されることをおすすめします。

だれか、Rails 2.0でdepotを作る手順とかまとめてくれないかなあ。


2008-01-14 (Mon) [長年日記]

_ [Rails] CookieStoreとセキュリティ(2)

ちょっと気になるのが、サーバが一度発行したクッキーは、HMACで使用する鍵を変えたりしない限り、ずっと有効だということだ。悪意のある第三者がクッキーを盗聴してリプレイを試みる、というケースについては、盗聴できたという時点で他のセッションストアの場合もセッションハイジャックが可能になるので、CookieStoreがとりわけ危険だというわけではない。気になるのは、ユーザがセッションの状態を任意の時点に戻すことができる点だ。アプリケーションの作りによっては悪さができそうな気もするのだけれど、実際のところどうなのだろう。

[Cookieとセキュリティより引用]

と書いたけど、問題になりそうな具体例を思い付いた。

RailsによるアジャイルWebアプリケーション開発 のサンプルのショッピングカートアプリケーションでは、カートの格納先にセッションを使用しているが、選択された商品をカートに格納する際に商品の価格をコピーする。 *1 これは、商品の価格が変更されても、カートに入っている商品の価格はカートに入れた時点の価格のままにする、という仕様になっているためだ。

ここで問題となるのが、CookieStoreではいつでもセッションの状態を 任意の時点に戻すことができることだ。 カートの内容も当然その時点に戻るので、最安値の時のセッションデータ を保存しておいて後で使用すれば、いつでも最安値で商品を購入できてしまう。

対策は簡単で、カートの保存先をDBにすればよい。

まとめると、CookieStoreに格納すべきでないデータは、以下のようなデータだ。

  • ユーザに知られてはまずいデータ
  • アプリケーションの動作に重大な影響を及ぼし、状態が変わりうるデータ。

後者については「アプリケーションの動作に重大な影響を及ぼす」だけだと、ログインユーザのIDすら格納できなくなるので、「状態が変わりうる」という条件を追加しないと使いものにならない。 ユーザIDに対応するユーザ情報(管理権限があるか、いつまで有効か、など)は「状態が変わりうる」のでCookieStoreに格納してはいけない。 ユーザIDについても、欠番になったIDを再利用しているような場合では問題が発生する。

上記のような判断をきちんとできる自信のない人はCookieStoreを使わない方がよい。 幸いCookieStoreにはサイズの上限があるので、あまりセッションに情報を格納しないスタイルにプログラマを誘導できるかもしれない。

*1  そもそもこの作りの筋が悪いという話はある。

_ [Rails] CookieStoreの有効期限

以下のようにセッションの有効期限をサーバ側でチェックすることができる。

before_filter :check_session_lifetime

private

def check_session_lifetime
  if session[:updated_at] &&
    session[:updated_at] + 1.hour < Time.now
    reset_session
    # 実際にはユーザに適切なフィードバックを返す。
    raise "session expired"
  end
  session[:updated_at] = Time.now
end

ただし、セッションに格納する情報に注意する必要があることには変わりない。

_ [Rails] Ruby on Rails の注文の多い料理店に入ってしまった話

Rails周りの不幸な出来事の原因はいろいろあると思うけど、その原因の一つはRailsプログラミング(あるいはRubyプログラミング・Webアプリケーションプログラミング)がその見かけほど簡単なものではないことだと思う。

Railsの見かけはどんどん簡単になっていく。scaffoldからpaginationが消えてすっきりしたり、MySQLをセットアップしなくてもSQLiteがデフォルトになってすぐに使えたり、CookieStoreがデフォルトになってセッションファイルでディスクを溢れさせるようなこともなくなった。 でも現実は厳しくて、何も考えずに「安心安全素敵」なWebアプリケーションができるわけもなく、さっきも書いたような罠があちこちに潜んでいる。 RubyもRailsも、もともと初心者が何も考えずにプログラムを書けるように作られているわけではない。 CやLispやJavaでもちゃんとしたプログラムが書ける人が、もっと楽にプログラミングできるように作られているだけだ。 見かけの簡単さにつられてプログラムを書きはじめた初心者の周りでは色々な問題が起こる。

でも本当の不幸の原因は、技術的なことよりも、平鍋さんの言葉を借りると「問題対私たち」という構図を作ることが難しいことにあるのではないかと思う。 毎日顔を合わせるチームのメンバの間でさえ「あなた対私」という構図に なりがちなのだから、会ったこともない人たちとコミュニケーションを取る場合はなおさらだ。 「それはお前がマヌケだからだよ!」と言いたくなることもある。 できる人・真面目な人ほど大変だろう。自分はダメな人間なので返事すら書かないことが多い。

とか書いてたら、Linuxとタコの話を思い出した。ぐぐったら生越さんの記事が出て来た。自分もこういう姿勢で人ではなく問題そのものに向き合えるようにしたい。 そのためには、場合によっては直接相手にしないことも適切な対応だろう。*1 スルー力という言葉は嫌いだけど。

あとは蛇足。

池上君は実は大学のクラスメートだった。でも在学中に話をする機会は少なかった。理由は池上君が現実逃避をしながらも無事卒業したのに対して、自分は バンド活動やRubyといった現実逃避に明け暮れたあげく、ついには数学科をドロップアウトしてしまったからだ。

文学部哲学科に変わったものの、一年留年して卒論をでっちあげて卒業した後、こうしてRubyを仕事にしてしまっている。今も現実逃避の真最中というわけ。ここまで来たら精一杯逃げ続けるしかない。

池上君も僕を見習ってもうちょっといい加減に生きたらいいと思うよ。 Rails 2.0ではCSRF対策のコードがデフォルトで入ったし、世界はちょっとずつマシになっている。

*1  ちゃんとしたレポートをもらってるのにたんに面倒で返事をしてないメールはいっぱいあります。念のため。めげずに催促してください。返事は保証しないけど。