徳丸さんのブログでの全く間違った指摘に対するコメント


徳丸さんとは論理的に議論をする余地がないので、議論をするつもりは全くありません。しかし、完全に間違った指摘をされているのでコメントしておきます。

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

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

トークンの有効範囲は?

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

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

全くの誤りです。

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

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

CSRFトークンとなるIDは以下のように生成されています。

DBで共有されているどころか、完全にランダムになっています。つまり

  • 誰とも共有していないランダムなキー

になっています。分かり易くいうとランダムキーであるセッションIDと同じです。このプログラムの問題を挙げるとすれば、

  • コリージョンを考慮しなければならないハッシュ値にSHA1を使っていること(SHA1はNISTでは「コリージョン」(衝突)を考慮しなければならないハッシュは使用禁止)
  • SHA1を使っているのにPHPのセッションモジュールのように衝突検出をしていないこと(私が実装した session.use_strict_mode のように衝突検知していないこと)
  • 時間ベースと疑似乱数による弱いランダム化(これはコメントで安全な/dev/urandomを使う方が良いと記載)

です。古いプログラムなのでここまでの変更はしていません。

このサンプルの場合、CSRFトークンは”使い捨て”のランダムキーで一度使われると削除され、2度と使えません。固定のCSRFトークンに比べ格段にセキュアーです。

指摘は完全に誤りなので追記で誤っていた旨のみ記載していただけると助かります。

因みに、徳丸さん。参照されているツイッターユーザーですが、ISO 27000に明確に書いてあることを書いていないなどとツイートされていた事があるので注意された方が良いと思います。

 

追記: Facebookでの議論を踏まえ、なぜこの仕様で安全なのか追加で解説しておきます。

  • CSRFトークンの生成はセッションID生成並みに安全(ただし、/dev/urandomのようなRNGの方が良いことは明白)
    • つまり、総当たり攻撃耐性もセッションID程度。これで危険ならセッションIDも使い物にならない。
  • 特定ユーザーと紐づけていない点が少し脆弱
    • ユーザーIDと紐づけしていないのは「ログインなし」のケースも考慮
    • セッションIDと紐づけしていないのは「セッションID再作成」のケースも考慮
    • 使い捨てのCSRFトークンをセッションに保存するのは、非効率。(大量のトークンが保存される&管理しなければならない)
    • セキュリティ対策は利便性と安全性のトレードオフ。このサンプルではコリージョンリスクを取って利便性(汎用性)を向上させている
  • このようなID生成にはコリージョン耐性のあるハッシュ関数と暗号理論的に安全なRNG(ランダムナンバー生成器)を使うと”十分”な安全性を得られる

コメントを残す

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

次の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="">