CSRF脆弱性対策

CSRF対策のtokenはセッションIDで良い

セキュリティ的にワンタイムトークン>セッションIDではない。
という話が、この辺の記事に書かれています。
高木浩光@自宅の日記 - クロスサイトリクエストフォージェリ(CSRF)の正しい対策方法
高木浩光@自宅の日記 - CSRF対策に「ワンタイムトークン」方式を推奨しない理由, hiddenパラメタは漏れやすいのか?


肝はこういう事のようです

  • tokenは外部のサイトから知り難い(実質知り得ない)ものでないといけない
    • セッションIDはcookieに格納される
    • セッションIDは『暗号学的に安全な擬似乱数生成系で生成されているはず』(引用)
      • 推測も事実上できない


補足すると、セッションIDを使用したCSRF対策tokenが漏洩している状態(大体XSS)だと、

ので、セッションIDが漏洩しうる状況だとワンタイムトークンもバシバシ突破されます。

はてなCSRF対策

はてな各サービスの CSRF 脆弱性対策について - はてなダイアリー日記
パッと見先程の話に準拠した対策に見えますが、
id:malaの指摘(livedoor クリップ)によると問題があるようです。
実は先程の話とは暗黙の前提に違いがあるのだと思います。
おそらく、1サイト(=1Webプリ)、1ドメインにつき、1セッションIDというのを前提にしているのでしょう。


はてなの場合は、セッションIDはhatena.ne.jpで設定されていて、
そのサブドメインの各サイトで共有しています。
1リクエストで完了する処理なら、XSS脆弱性のあるはてなのどれかのサイトから、
XSS脆弱性のないはてなの別のサイトにtoken付きのリクエストを飛ばして強制的に実行できてしまいます。


もちろん、セッションハイジャックをしてしまえばtokenがサイト間で共有されてなくても、
いろいろできてしまいますが、それについてはこういう事のようです。

原則を補足してみる

tokenは外部のサイトから知り難い(実質知り得ない)ものでないといけない

tokenは(同一団体が運営する親ドメインが同じサイトであっても)外部のサイトから知り難い(実質知り得ない)ものでないといけない


この原則を満たさないと、XSS脆弱性のあるサイトから兄弟サイトへのカジュアルなCSRFは止められませんよ、と。


ワンタイムトークンを使うとしても保存先が兄弟サイトで共有されるセッション変数であれば、

  1. 脆弱性のあるサイトAでワンタイムトークンのhidden fieldを含むページのHTMLをXHRで取得
  2. スクレイピングでワンタイムトークンを取得
  3. 脆弱性のない兄弟サイトBに先程のワンタイムトークンを含むリクエストを送信

とかできちゃうので、結局、「セキュリティ的にワンタイムトークン>セッションIDではない。」のも同じですよ、と。