Hatena::ブログ(Diary)

kizashi1122の日記

2012-09-17

Seasar2 の dbsession について

14:23 | Seasar2 の dbsession についてを含むブックマーク

仕事で Seaser2 の dbsession を使っている。

セッションの中身を DB に保存することができるため、アプリケーションクラスタリングが容易にできたり、メモリの節約になるなど大きなメリットがある。

この機能は自前で作ろうかと考えていたところだったので、非常にありがたかった。しかし、テストを重ねていくうちに、この dbsession を使っているといくつかのセキュリティに関する脆弱性があることがわかった。

それらは「XSS後のセッションハイジャックの予防策が設定でできない」「セッション固定化(のうちのセッションアダプション)ができてしまう」である。

これらの脆弱性対策には、

  1. アプリ側での防御策をとる(dbsession を外側から拡張することも含む)
  2. dbsession 側で修正および拡張可能にしてもらう
  3. dbsession 以外の選択肢をとる(要は使わない)

があると思う。3 つ目も考慮しないといけないけどここでは触れないこととする。

この脆弱性対策は、実は素の Tomcat6 のセッション管理ではクリアできている。

dbsession 機能と、通常の Tomcat6(6.0.35) のセッション管理機能について比較してみる。

dbsessiontomcat6
セッションクッキーの httpOnly 属性設定できないserver.xml で設定可能
セッションアダプション脆弱性おこるおこらない

大きくこれが挙げられると思う。

Cookie には httpOnly という属性があり、これを On にしておくと、JavaScript からは操作できなくなるため仮に XSS 脆弱性により悪意のある JavaScript が実行される場合でもセッションIDを盗まれる(セッションハイジャックをされる)可能性が下がるということである。生の Tomcat6を使っている場合でもデフォルトではこの設定は有効ではなく server.xml (context.xml) の Context 要素の useHttpOnly 属性を true に明示的に設定しなければならない。

また Tomcat6 では、管理されている(有効なセッションの)セッションID 以外は受け付けないので、セッションアダプション(任意のセッションIDをセッションIDに固定化させること)による脆弱性が起こらないのだ。これは CookieセッションURL につけられたセッションともにである。

さて、個別に見てみるとする。

httpOnly 属性について

これは Cookie クラスのアクセサメソッドでつけることはできないので非常にやっかいである。

Tomcat 自身も内部処理ではCookieオブジェクトを分解して文字列を組み立てた一番後ろに "; httpOnly" を付与している。


アプリでの対応

これはアプリ側で、無理やりだが対応はできる。

それは Filter などでセッションクッキーを探し出して、レスポンスに毎回付与するというやり方である。

キーや値を変えていないとはいえ、毎回更新するのは気持ちが悪い。毎回レスポンスにSet-Cookieヘッダがつくことになる。決してスマートとは言い難い。

アプリセッションが生成されるタイミングが明確にわかるのならばその処理のレスポンスに付与してもよいかもしれない。

	response.setHeader("Set-Cookie", "S2SESSIONID=" + c.getValue()
			+ "; Path=" + c.getPath() + "; HttpOnly");

追記:なぜか↑がうまくいかなくなった・・・(9/18) 家ではうまくいってたのに・・・。

dbsession での対応

もちろん dbsession 側でも対応してほしい。

タイミングは SessionIdUtil#writeCookie だろう。ここなら SessionFilter の initParam も取得しているし、設定する場所も他の Cookie の属性と同じくできる。

同クラスからは、response も参照できるので、Cookie を分解して上記のような処理をすることは可能なはずだ。

するとセッション作成時に一回だけ処理するだけでよくなる。

セッションアダプション脆弱性

Tomcat6 でこの脆弱性がおこらないのは、Tomcat6 は自身が発行したセッションID以外は受け付けないからである。

org.apache.catalina.connector.Request#isRequestedSessionIdValid で管理されているセッションIDかどうかを内部でチェックしている。

ところが dbsession では、発行したセッションを一括して管理していないため、リクエストで飛んできたセッションID(Cookie 由来、URL 由来ともに)は、"hoge"

であろうが空文字であろうがそれをセッションIDとしてしまうのである。これはPHPでもおこるらしい(どのバージョンかはよく知りません)がPHPアプリセッションIDを再発行できるためセッション固定化はかなり防げるのである。

さて対策だが、Tomcat6 がやっている「未知のセッションIDをうけつけない」か、PHPがやっている「セッションId振り直し」のどちらかで対応したい。

前者は、セッションIDを発行する dbsession 側でないと管理できないだろう。

後者は、Tomcat6 ではできない。だが、dbsession は逆に改良すればできるのではないだろうか?

アプリの対応として、SessionFilterを複製したものを自前でつくり、、、と考えたがSessionIdUtil のフィールドにアクセスできなくなる。

よしんばここがクリアしたとして、次は、S2HttpServletRequestWrapper を継承したクラスを作ろうとおもったが、S2HttpServletRequestWrapper の

フィールドは Private なので子クラスからアクセスできず、自前の対策断念することになった。

こちらも dbsession 側での対応が求められる。僕が対応するなら前者だろうか。Tomcat6 を参考にすることができるし、割と実装がイメージしやすい。

この脆弱性は、気持ち悪いので今すぐにでもなんとか回避したいところなんだが。。。

URL Rewriting によるセッションID付与だけでも禁止する設定があればまだリスクは下がるだろう(Tomcat6 では disableURLRewriting はデフォルトでtrue だが ;jsessionid でつけられた値は、CookieセッションIDがない場合はセッションIDとして認識されてしまうので注意。Tomcat7なら TRACKING-MODE を COOKIE のみとすることにより、URLの ;jsessionid を参照しなくできるよう) ええとここでのリスクが下がるというのは、攻撃する側としても Cookie を加工(リクエストヘッダを加工)するよりは URL を加工するほうが簡単というくらいの意味あいです。

結論として、ここはアプリで解決はできなさそう。

できるのであれば教えてほしい。

そもそも dbsession の使い方

dbsession は便利であるがこのあたりの特性をよく利用して使わないといけないと今回いろいろ調べていて強く感じた。

セッション無効化について考えてみる。

セッションが無効化されるタイミングは2つあって、それぞれ

  1. 明示的にログアウトしたとき(session.invalidate() が呼ばれたとき)
  2. タイムアウトしたとき

である。Tomcat6 のセッション管理機構を使う場合は、上記の2つはそれぞれサーバ側でセッションが無効化されてしまうのである。

無効化されたあとでもクライアントには古いセッションIDはあるが、それでアクセスしてもTomcat6 は受け付けないので、新しいセッションIDが振られるのである。

しかし、dbsession に関していうと前者の session.invalidate() の際は DB のデータをクリアすることしかしていない。内部的にはそのセッションは無効化されて新しいセッションIDが振られていたりするが、肝心のセッションクッキー(つまりセッションID)はそのままである。次回アクセスしたときに、そのIDが上記セッションアダプションの問題により再利用されてしまう。

セッションクッキーなんてブラウザ落としたら消えるじゃんと思うかもしれないが、最近のブラウザはタブを保存する際にセッションクッキーまで保存しているようであり(おそらくですが)、セッションクッキーは揮発性であるとはもはや考えないほうがいいのかもしれない。

まとめると、dbsession に関してはアプリ側としては

  1. Cookie の有効期限(max-age)はセッションクッキー(-1)ではなく明示的に1h(3600 s)などと設定する(web.xml) (念のため上記時間にあわせてDBも定期的にクリーニングする。念のためというかデータが増えるのは嫌だから必ず消すべき。)
  2. session.invalidate と同じタイミングで、Cookie を削除する(有効期限を過去にする)

が今できるベストプラクティスではないかと思う。そうすると見かけ上、ログアウト後もセッションタイムアウト後も新規にセッションIDが振られることになる。

そしてさらに付け加えるなら、上記の httpOnly の設定である。

となるとやはりセッションアダプションだけが気になるのである。

ここは対応していただきたいなぁと思う。

訂正
  1. Cookie の有効期限(max-age)はセッションクッキー(-1)ではなく明示的に1h(3600 s)などと設定する(web.xml) (念のため上記時間にあわせてDBも定期的にクリーニングする。念のためというかデータが増えるのは嫌だから必ず消すべき。)
  2. session.invalidate と同じタイミングで、Cookie を削除する(有効期限を過去にする)

1. はダメです。

明示的に時間を設定したときに、仮に1hとすると、この1hは誰も更新してくれないので、普通に1h使い続けていても、突如セッションタイムアウトになることがあります。

問題が元に戻ってしまった。

おそらく、

  1. このクッキーの max-age をアクセスの都度更新する。

をすれば意味があるかもしれません。


なんだかなぁ・・。

結局こうやった(9/22)

下記でいうところの「セッション無効化」は、


  SessionIdUtil.writeCookie(request, response, UUID.create());
  session.invalidate();

と考えてほしい。単純に invalidate() するだけでは sessionid が使いまわされることになる。

  • Cookie の有効期限(max-age)はセッションクッキー(-1)ではなく明示的に1h(3600 s)などと設定する(web.xml)
  • 念のため上記時間にあわせてDBも定期的にクリーニングする。念のためというかデータが増えるのは嫌だから必ず消すべき。
  • ログアウト時はセッションを無効化する
  • ログイン画面に遷移したタイミングでセッションを無効化する
  • パーシステントクッキーなので、誰かが期限を明示的にのばしてあげないといけない。Filter で、Cookie の中身を分解し、文字列化して response.addHeader() した。この際、chain.doFilter(requestWrapper, responseWrapper); の前で実行しないとだめだった。
    • ここで httpOnly をつけている。

とまぁこんなかんじである。

リクエストごとにCookieが書き換わるのがなんかアレなかんじである。

それに苦肉の策でログイン画面表示時に無効化しているので、同じブラウザで2枚ひらくともうアウトである。パーシステントなクッキーなのでブラウザプロセスも関係ない。Cookieは共有される。

ここは後々なんとかしたいところ。

トラックバック - http://d.hatena.ne.jp/kizashi1122/20120917

2012-08-25

何観たっけ?

| 01:30 | 何観たっけ?を含むブックマーク

スーパー![11]

グロさがいきすぎてて、逆に笑える。でもラストは普通にいい落とし所にもっていったな。

ダークナイト・ライジング[12]

いつもは箕面109シネマズなんだけど、時間帯の都合でマイカル茨木まで見に行った。

いやぁ、期待していたよりよかったですよ。あまり長さを感じさせません。

ちゃんと理解しようと思うと、ダークナイトだけでなくて、その前の「バットマン・ビギンズ」も見る必要があります。

アン・ハサウェイはあまり好きな女優ではないですけど、この役は良かったとおもいます。

カウボーイ&エイリアン[13]

もうタイトルからしておかしい。

みてみるとそのまま。もうギャグの世界なんだけれど、ダニエル・クレイグが渋すぎることと、ハリソン・フォードが出演しているだけでいい映画に見えてしまうということで、このちゃんちゃらおかしい世界観をそこそこまじめに見ることができる。

つっこみ出すとキリがない映画なんだけど。ほんとに。

オリビア・ワイルドは「トロン」以来だったけど、いや、よくこの役引き受けたよな。。。

しかし、アメリカ人の考える「エイリアン」にはもううんざり。

スーパー8クローバーフィールド、あのあたりと同じですな。

トラックバック - http://d.hatena.ne.jp/kizashi1122/20120825

2012-06-25

イヤホン購入

00:24 | イヤホン購入を含むブックマーク

また断線させてしまった。

なので、ヨドバシカメラで770円の同じイヤホンを購入。

僕にとって、イヤホンは消耗品。

パナソニック カナル型イヤホン ブラック RP-HJE150-K

パナソニック カナル型イヤホン ブラック RP-HJE150-K

ワイルドスピードMEGAMAX [10]

| 00:11 | ワイルドスピードMEGAMAX [10]を含むブックマーク

あー、これ続きものだったんだー。

まあ単品でも楽しめる作りになってるけどー。

まぁ何も考えずに楽しめますよ。

ダークシャドウ[9]

| 00:04 |  ダークシャドウ[9]を含むブックマーク

劇場で見た。

まーまー、ティム・バートンジョニー・デップって感じです。

ドラキュラもの。

クリストファー・リーカメオ出演には思わず感激してしまった。

ミシェル・ファイファーは相変わらず、年老いても美人ですなぁ。

ノーカントリー[8]

| 00:03 | ノーカントリー[8]を含むブックマーク

なんだよこれ。何がおもしろいんだ。

どう解釈すればいいんだ?

コーエン兄弟・・・。よくわからん。

トラックバック - http://d.hatena.ne.jp/kizashi1122/20120625

2012-04-22

バトルシップ[7]

22:18 | バトルシップ[7]を含むブックマーク

アメリカ様のつくったわかりやすいストーリー。

あれ、これ、アルマゲドンだっけって思うくらい、アルマゲドンぽいし。

もっとトランスフォーマーちっくなメカニカルな動きがあってもよかったと思う。

それにしてもアメリカ人の描くエイリアンってなんでああなんだろうか。

日本人にはちょっと受け入れがたいね。

しかし提督役のリーアム・ニーソン、は同時公開されている「タイタンの逆襲」にもゼウス役で出ている。大丈夫なのか? いやそれを言うと、このバトルシップで主役のテイラー・キッチュは、同時公開されているディズニー配給の「ジョン・カーター」も主役なのだ。ぼくが心配することではないが大丈夫なのか?

ウォール・ストリート[6]

22:14 | ウォール・ストリート[6]を含むブックマーク

勝手だが、もっとドロドロした頭脳戦があるのかと思っていた。

なんかいい感じで終わってしまうし。

タイタンの逆襲[5]

22:12 | タイタンの逆襲[5]を含むブックマーク

うーん。もう少し楽しませてくれてもよかったのではないだろうか。

戦いのシーンが見所なのに、さくっと勝ってしまうし。

女王役のロザムンド・パイクは綺麗なんだけど、若くなくていまいち萌えないのだが、どこかで観たことあるなーと思ったら、「サロゲート」だった。同じようにいまいちだなーと思った記憶がある。

シャーロック・ホームズ シャドウゲーム[4]

22:09 | シャーロック・ホームズ シャドウゲーム[4]を含むブックマーク

1作目もおもしろかったが、今回の作品も面白かった。

次は・・・もちろんあるはず。

期待したい。

シャッターアイランド[3]

22:06 | シャッターアイランド[3]を含むブックマーク

観たのは先月だっけか。

書くのを忘れていた。

うーん。解釈が難しいところ。

もう一度よく観ると、ちゃんと解釈できるのかもしれないが、そこまで観たいと思える作品でもない。

トラックバック - http://d.hatena.ne.jp/kizashi1122/20120422

2012-02-04

ラスベガスをぶっつぶせ [2]

01:18 | ラスベガスをぶっつぶせ [2]を含むブックマーク

見ました。

来週からビジネスでアメリカに行き、その先がラスベガスサンフランシスコということもあって、ラスベガスの雰囲気をみるために、この映画をチョイスした。


うん。映画として面白かった。とってもわかりやすい映画。実話を元にしているからというのもあるのかな。

MITの学生が確率論を駆使してラスベガスで金儲けを企み、そして・・・という話。

主役のジョン・スタージェスは普通の男の子っぽくて、でもかっこよくて、でも普通っぽいというこの手の映画にはうってつけっぽい感じの俳優だ。

ちなみに「ラスベガスをやっつけろ」のほうではない。あれは確かテリー・ギリアム監督のやつだ。まだみてない。

もう2月なのにまだ映画を2本しか見ていないという事実に愕然としています。

トラックバック - http://d.hatena.ne.jp/kizashi1122/20120204