徳丸さんのブログに対するコメント


最初、書いた時はユーザーが一人だけと頭にあったので思いっきり誤解していました。確かに複数ユーザーの場合は真正性に問題があります。修正版の差分をアーカイブを更新しておきました。

本題のブログはこちらです。

書籍『Webアプリケーションセキュリティ対策入門』のCSRF脆弱性

トークンの有効範囲は?

トークンがDBに保存される場合、トークンの有効範囲が気になるところです。大垣本および第二版のソースを見ると、トークンを保存するテーブルの定義は以下の通りです。

sha1がトークン、createdが生成日時を保持します。
シンプルな構造ですが、これだとトークンは、ユーザーやセッションを超えて、アプリケーション全体で共通になっています。これはまずそうですね。
トークンをホテルの部屋の鍵に例えると、こうです。大垣方式の鍵は、ホテルの全ての部屋に共通で使える鍵です。本来は、鍵は特定の1部屋のみに使えるべきですが、そうなっていないのです

複数ユーザーの場合、セッションIDが他のユーザーに見えると困ることと同じでユーザーまたはセッション毎に紐づけしないと不正な操作を外部からされる可能性があります。

脆弱だ、とされているプログラムはこちらです。

Webアプリケーションセキュリティ対策入門の付録を更新

修正した差分はこちらです。

EXCLUSIVE TRANSACTIONでトランザクションをシリアライズすることと、$form_idにハッシュ化したセッションIDを付けてユーザーに紐づけするようになっています。

これで複数ユーザーになった場合でも、他のユーザーが他のセッションにCSRFトークンを利用できなくなると同時に、トランザクションでレースコンディションを防止できます。1つ問題なのはセッションIDが切り替わった場合です。これに対処するには$_SESSIONに最後のIDを保存しておいて、現在のIDと違う場合に前のIDを使うように変更すると対応できます。

使い捨てのCSRFトークンは、固定または半固定のCSRFトークンよりかなり安全ですが問題もあります。使い捨てのCSRFトークンはフォームのみでなく、大量データの一覧にも使うことができます。セッションに使い捨てのCSRFトークンを保存すると、セッションデータが大きくなりすぎてパフォーマンスに影響を与えてしいます。GCも性能に影響を与えます。

使い捨てのトークンを実装する場合、memcachedなどの自動的に有効期限が切れるデータベースを使うと便利かつ良い性能を期待できます。memcachedを利用する場合、$form_id . “.lock”などのロックレコードを使ってロックしないと、レースになる場合があります。

時々やってしまうのですが、大きな勘違いをしていました。サンプルとして大きな欠陥でした。時間が無いから、といって斜め読みすると危険です(汗

認証系のライブラリなどでも今回間違えていたような、この種類の前提ミスがあることが時々あります。他山の石として注意してください。

指摘頂いた徳丸さん、ありがとうございました。また、最初に投稿したときは誤解していて失礼致しました。

 

 


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">