ネタもと:CSRF対策に「ワンタイムトークン」方式を推奨しない理由 from 高木浩光@自宅の日記
CSRF対策に「ワンタイムトークン」を用いるという話が出ると、本物のプログラマ達は、まず図5の実装(でwinidを乱数にする)を頭に浮かべるのではなかろうか。
なるほど。本物のプログラマは、そういう風に考えるのかぁ。
でも、ごめんなさい。エセプログラマな私が意見するのもなんですが、やっぱり、ワンタイム・トークンを使います。もとい。ワンタイム・トークン“も”使います。
なぜなら、対策しなければならないのは CSRF だけではないので、グローバル変数1個に「トークン」を入れる方法なので、これでは同時編集ができなくなる
ように“したい”からです。
Windows アプリケーション(またはスタンドアロン アプリケーション)の場合、ウインドウの生成は、作り込むわけですから、好きなように制御できます。編集画面を1枚だけしか開きたくない場合、そのように実装できます。
ところが、Web アプリケーションの場合、そのような制御は出来ません。複数のブラウザを起動して、別々にリクエストを投げれば、何枚でも編集画面が開きます。すでに別のアプリケーションとして存在しているものを使うわけですから、それの制御までは出来ません。
ログインの箇所で制御しようとしても、ユーザが明示的にログアウトしてくれるかどうかわからないので、あまり期待できません。Internet Explorer の場合、[ファイル]メニューから[新規作成]すれば、表示されているのと同じセッション、同じ URL で画面が開きます。
このように、ウインドウの生成を制御する方法で、編集画面を1枚だけに抑制することは困難です。なので、他の方法を探さなければなりません。
高木氏は今回、“更新”処理を取り上げています。しかし、“追加”処理の場合はどうでしょうか。
更新処理の場合、何度ポストされても、同じデータが送られてくるので、何度更新してもデータは変わりません。しかし、追加処理の場合、同じデータが何度も送られてくるのは、喜ばしくありません。様々なサイトで、「送信ボタンを押すのは1度だけにしてください」と、注意書きがあるように、ここは1度に制限したいところです。
実際、コミュニティには、「複数回のリクエストを1回だけに制御したい」という質問が、チラホラあります。記事の方に「ASP.NET 1.1 「リロード」で、データを2重登録させない」というエントリを設けていますが、参照回数が 570 回程度。検索キーワードは「リロード ポストバック 戻る」が多いですが、「多重投稿+防止 連続+ボタン 連続要求 連続ポスト」というキーワードもあります。
クリックでいいところを、誤ってダブル・クリックするかもしれない。サーバでの処理がもたつき、ユーザがイラついて複数回クリックするかもしれない。全然回答がないので、大量に送りつけてやれ。
十分に考えられるシナリオではないでしょうか。
Windows アプリケーションの場合、イベントハンドラの出口で待機イベントをキャンセルすることで、イベントの発生を1回だけに抑制することが出来ます。しかし、Web アプリケーションの場合、サーバ側でクライアントで発生してしまったイベントを制御することが出来ません。
同じように更新も、高木氏が例に挙げられているように、違うデータを更新するなら、それはそれでいいでしょう。しかし、同じデータが表示されていたら?片方は書き換えて更新、もう一方はそのまま更新されたら、どの様にデータを扱えばいいのでしょう?あるいは、ユーザはどうしたかったのでしょうか?ここでセッション ID だけが判別 ID として用いられていたら、このような(開発者として、かもしれませんが)イリーガルな更新処理を防げません。
ここで防ぎたいのは、連続しない画面遷移、悪意ある人からの攻撃だけではありません。連続した画面遷移であっても、同じ内容での複数回の要求、矛盾する複数の要求、悪意のない人の操作ミスなどによる、データ破損(汚損)も防ぎたいのです。
データが破損(汚損)することを防ぐ。その為に、同じセッションからのリクエストを1回だけに絞る。その実現方法としてワンタイム・トークンを使う。その弊害として、同時編集できなくなる。どうしてもやりたいなら、セッションが別々になるような接続をして、やってくれ。いかがでしょうか?
投稿日時 : 2006年4月13日 21:44