<前の日記(2006-03-27) 次の日記(2006-03-31)> 最新

おおいわのこめんと (2006-03-30)


2006-03-30

[Security] えび日記: CSRFの説明に追記

(4/2、この項に別記事で追記。)

ええと、この議論はずっと続いていますね。こういう時間かかる話はできれば年度明けてからやろうよ(笑)。

※ちなみに「CSSXSS」と呼ばれている問題の本質は「クロスドメインで任意の HTML の内容が読み取れてしまう」という点です。これは XSS とはあまり関係ありませんし、ある意味 XSS よりも危険です。その呼称は誤解を招くと個人的には思っています。 (「えび日記」より引用)

この脆弱性の存在を根拠に「いわゆる高木方式は良くない、安全な他の方式にすべきである」という議論がよくあります。 いつも反論してるのですが、割と議論が噛み合わないのは、ひょっとしたら僕が「いや、高木方式で安全なんだ」と 主張しているように思われているのかなぁ、とふと感じました。

実はそうじゃないんですよね。僕の主張は、「いや、その状態ならパスワード毎回入力以外はどんな対策をやったって無駄だ」 なんです。*1

別ドメインのスクリプトから hidden フィールドを読みとれるという前提で、 クッキーでセッション管理がなされている一般的な Web application にログインしている状況を考えます。 もちろんその場合、「いわゆる高木方式や、その亜種であるセッション鍵のハッシュを hidden に格納する方法」を 実装している場合、hidden field から正規リクエストに必要な情報を抜き出され、CSRF攻撃が成功します。

しかし、その場合、ワンタイムキーのような手法を用いていても、 当然 hidden フィールドからワンタイムキーを盗んでいく事が可能なので、 CSRF攻撃はやっぱり成功します。 Web ページから (JavaScript から、と言い換えても良い) 見たリクエストの要素はザックリ考えると 「URL, Referer, Cookie, フィールド値」の4要素ですが、 このうちのフィールド値に入れるべき値を別ドメインのページから盗聴できるという仮定の元では、 他の要素のうち URL は正規リクエストに合わせる事ができ、 Cookie は放っておいてもブラウザが勝手に正規の値を入れてくれますから、結果的には 「Referer チェックをしていない限り偽装リクエストは送出可能」という結果が 導出されます。あれ、一番役に立たないと思われている手法が安全なのか?(笑)

そういう意味で、「ユーザが秘密情報を入力しなくても Submit をクリックすればリクエストが送出される状態」 のページについては、どんな対策を実装していても偽装リクエストが送出できる事が、示せてしまうんですね。 「無駄」ってのは、要するにそういう意味です。

ちなみに、正規ブラウザに不正なページを送り込んで攻撃を行なうという CSRF の前提では Referer 偽装を完璧に防ぐ事は一応可能ではあるものの、それには HTTP Redirection や META refresh など 色々な動作に応じてブラウザは相当微妙な動作をするので、その仕様を全部検討しないといけないことと、 いわゆる「Norton 様」(Referer 不送信クライアント)の存在を無視できない事から、 あまり現実的な対策とはいえません。

あと、多分ですね、もう1つ議論がかみ合わない理由は、結構皆さん Cookie 盗聴そのものをかなり特別に 気にされているのではないかと感じています。これは想像で、ひょっとしたら違うかも知れないけど。

Cookie はもともとは「プライバシーに関する情報を直接入れて、それによって 送出ページを選択する」という使い方の方がメジャーで、 そのため昔は「cookie 漏洩はプライバシー漏洩だからヤバイ (1)」という議論がありました。 そして、セッションIDの格納場所として使うようになってからは、 「cookie 漏洩はセッションハイジャックされるからヤバイ (2)」という認識になって、 それ以来すごくみんな気にしている。僕もすごく気にしている :-)。

もちろん、実際の web application で session ID の Cookie 洩れたらヤバイですよ。それは事実。 そこを僕が否定していると思われると、それは困る。

でも、「なんでやばいのか」をよーく考えると、非常に直接的・限定的な意味で かつ (1) 的には全然やばくないわけですよ。 えーー、っと思うかも知れないけど、所詮単なる乱数なんだから。 例えば、ログイン機能だけあって他には何もできない空っぽな web application 考えるとですね、 session ID 盗まれても何もできないから恐くないわけ。極論だけどね(笑)。

本質的なのは、(2) のうちの「セッションハイジャックされるから」 の部分であって、さらに上のような極論を踏まえてその本質を考えると、 セッション情報を入手されたことそのものではなくて、 「セッションを乗っ取られると、ログインユーザの権限で好き放題攻撃者にやられる (情報盗聴を含む)」のが (空じゃない現実的な web application については) 嫌なわけ。そりゃそうだよね。 で、その文脈を考えると、別に cookie 盗聴に限らずセッションを乗っ取れる攻撃は全て、例えば CSRF だろうと それこそスパイウェアだろうと、あるいは「後ろから頭頂を金槌でひっぱたいて気絶させて乗っ取る」攻撃 (AA略) だろうと ヤバイはず。

で、それでも「中でも session ID 盗聴はなんでもできちゃうから超やばいじゃん」という反論はあるかも知れないけど、 普通の「ウェブアプリをひとしきり使ってログアウトしておしまい」という使い方や、 「ウェブアプリを開いてずーっとセッション維持しっぱなし」という使い方を考えて、 ちゃんとした「ログアウトした session ID は無効になる」ような実装を考えると、 「フィールドの値が読めて好きなリクエストが JavaScript から送れる *2」 CSRF 発動状態ってのは、書き換え系の攻撃に関して session ID 盗聴と同じくらい なんでもできる。なぜなら、ユーザが気がついてログアウトするまでの間、 複数のリクエストをタイミングを制御しながら連続的に生成できるから。

まぁだから攻撃の複雑さという意味ではちょっとだけ難しくなるのは事実だけれども、 所詮は鍵を植木鉢の下に隠すかポストの中に隠すか位の違いでしかなくて、 鍵を泥棒の手の届かないところに管理するというレベルではないんで、 別方式を提案・推奨する時にその辺りちゃんと議論せずに「こっちの水は甘いぞ」ってのは、 個人的にはちょっと無責任だと思うけどなー。

そういうわけで、「hidden フィールドが盗み見られるから『いわゆる高木方式』は単純で危険、 他のややこしい安全な手法にせよ」という論調はそろそろやめませんか。僕が特に異論を持っているのは後半部分で、 少なくとも「他の方式なら安全」という主張の部分は間違いの可能性が高いです。 それよりは「フィールド盗み見ることができるからみんな危険、とっととブラウザ直しやがれゴルァ (AA略)」という方が 建設的だと思います。

あと、「ブラウザの脆弱性は考慮しない」という主張も誤解を受けている気がしますね。 (ひょっとしてここが一番本質か?)

もちろん、基本的ポリシーはこの言葉の通りで、例えばいまさら「Mosaic ではこういうバグ仕様だったんだ」 とか言われたり、得体も知れないバグバグでドマイナーなブラウザ取り上げて 「このブラウザではこういう仕様なんだから」といわれても、この言葉でお引き取り頂く事に しています。

ただ、このCSRF周りの件に関して、少なくとも僕が「ブラウザの脆弱性は考慮しない」って言っているときは、 単に「ブラウザが悪いのは IE だろうと Mozilla だろうと知ったこっちゃない」という 単純な主張ではなくて、上に長々と書いたような背景を踏まえているつもりです。 要するに原理的にどうしようもないんですよ。

逆に例えば、昨年5月頃の Wiki の添付ファイル XSS について、 FreeStyleWikiに パッチを送った 時には、IEの「Content-type を無視して HTML を表示する」という バグ仕様に対応するために、IE の時は Content-disposition を付けるような コードを送った経緯があったりします。問題が明らかで、かつ対策すれば本質的に問題を回避できるなら、 それは少なくともメジャーブラウザ相手ならやっておいたほうがいい、と言うのは 原則論とは別の現実的な意味での大人の対応で、それを否定する気は毛頭なかったりします。 *3 セキュリティ屋がそういう意味で現実的対応をとるのは当然ですからね。

まぁあと最後に、「方式が根本的に危険」なのと、「方式は間違ってないけど現実論として他のがヤバイから なんとかしようぜ」というのは、根本の話が違うんで、その2つはちゃんと区別して議論しないといけません。 今年度僕が扱ってきたセキュリティホールでもこの手の「本来の責任のある人とは別の人が対処しなきゃいけない」 セキュリティホールになりそうだったのは多々あって、*4特にそういう件では報告の方法や文面などに普段以上の配慮を要します。 ある意味では、僕を含めてこの手のセキュリティホール屋ってのは人のプログラムの動作を非難するのが宿命なんで、 その辺りの「本来誰が対処すべきなのか、現実には誰が汗を流さなきゃいけないのか」、ってのの区別は 少なくとも僕はちゃんと意識しているつもりです。

これくらいで気持ちを判ってくれると嬉しいんだけどなぁ。

*1 さらに、他ドメインのページのデータを任意のタイミングで読みとることができてしまう場合には、どんな対策も存在し得ない。

*2 実際は「フィールド値を任意のサイトに送れる」だけでも十分。どこかのサイトで受信してから、 次の操作を指示するページをサーバ側で動的に生成すればいいからね。

*3 そう言えばこのサイトも自分では使わないIEのための対策コードが入っているなぁ :-)。 セキュリティ対策じゃなくて CSS のカバー範囲と動作の安定性の対策ですが。

*4 例えば Ruby の脆弱性による tDiary の脆弱性発現は、 実は最初は Ruby の微妙な仕様の落し穴の問題として tDiary に報告して回避対処をしてもらうつもりだった (Ruby 側は深刻でない仕様の問題として公開の場にバグレポートするつもりだった)のだが、 良く考えるうちに回避方法が存在しない事が判って、Ruby 側に修正を要する仕様レベルの脆弱性としてレポートする ことになりました。

本日のツッコミ(全3件) [メッセージを送る]
えむけい (2006-03-31 04:23)

リンク先の
開発者のための正しいCSRF対策
http://www.jumperz.net/texts/csrf.htm
によると、POSTで画面を生成すればCSSXSSではhiddenフィールドの値を「読めない」のだそうです。
したがって(CSSXSS対策に限れば)「いわゆる高木方式」を避けるのはContent-type無視問題対策と同種の対策であると言えるのではないですか? それとも「読めない」という主張自体が誤りなのでしょうか?

えむけい (2006-03-31 04:33)

よく考えたらPOSTで画面を生成することと「いわゆる高木方式」(セッションIDをそのままhiddenフィールドに使うこと)は直交していますね。失礼しました。

おおいわ (2006-03-31 06:00)

ええっと、その「直交している」で答えでいいですよね? :-)
「改良案」は改良されているようで本質的に同じなので、別の対策法で一方が回避できるなら、そのまま他方に適応できることが多そうです。

本日のTrackBacks(全1件) [TrackBack URL: http://www.oiwa.jp/~yutaka/tdiary/trackback.rb/20060330 (note: TrackBacks are moderated: spams will not be shown.) ]

開発者のための正しいCSRF対策 高木浩光@自宅の日記 - クロスサイトリクエストフォージェリ(CSRF)の正しい対策方法 こめんと(2006-03-30) 最近Webアプリ自体組まないんですけど… ...


大岩 寛 (おおいわ ゆたか) <yutaka@oiwa.jp.nospam ... remove .nospam> .

Copyright © 2005-2014 Yutaka OIWA. All rights reserved.
Posted comments and trackbacks are copyrighted by their respective posters.

記事の内容について (Disclaimer / Terms and Conditions)