CSRF脆弱性対策
CSRF対策のtokenはセッションIDで良い
セキュリティ的にワンタイムトークン>セッションIDではない。
という話が、この辺の記事に書かれています。
高木浩光@自宅の日記 - クロスサイトリクエストフォージェリ(CSRF)の正しい対策方法
高木浩光@自宅の日記 - CSRF対策に「ワンタイムトークン」方式を推奨しない理由, hiddenパラメタは漏れやすいのか?
肝はこういう事のようです
- tokenは外部のサイトから知り難い(実質知り得ない)ものでないといけない
補足すると、セッションIDを使用したCSRF対策tokenが漏洩している状態(大体XSS)だと、
- セッションハイジャックが出来る
- 正規のユーザと同じように操作できる
- 読み込ませたJavaScriptで以下の繰り返しで行うことで、セッションハイジャックをしなくても一連の画面遷移を再現できる
ので、セッションIDが漏洩しうる状況だとワンタイムトークンもバシバシ突破されます。
はてなのCSRF対策
はてな各サービスの CSRF 脆弱性対策について - はてなダイアリー日記
パッと見先程の話に準拠した対策に見えますが、
id:malaの指摘(livedoor クリップ)によると問題があるようです。
実は先程の話とは暗黙の前提に違いがあるのだと思います。
おそらく、1サイト(=1Webプリ)、1ドメインにつき、1セッションIDというのを前提にしているのでしょう。
はてなの場合は、セッションIDはhatena.ne.jpで設定されていて、
そのサブドメインの各サイトで共有しています。
1リクエストで完了する処理なら、XSS脆弱性のあるはてなのどれかのサイトから、
XSS脆弱性のないはてなの別のサイトにtoken付きのリクエストを飛ばして強制的に実行できてしまいます。
もちろん、セッションハイジャックをしてしまえばtokenがサイト間で共有されてなくても、
いろいろできてしまいますが、それについてはこういう事のようです。
原則を補足してみる
tokenは外部のサイトから知り難い(実質知り得ない)ものでないといけない
↓
tokenは(同一団体が運営する親ドメインが同じサイトであっても)外部のサイトから知り難い(実質知り得ない)ものでないといけない
この原則を満たさないと、XSS脆弱性のあるサイトから兄弟サイトへのカジュアルなCSRFは止められませんよ、と。
ワンタイムトークンを使うとしても保存先が兄弟サイトで共有されるセッション変数であれば、
- 脆弱性のあるサイトAでワンタイムトークンのhidden fieldを含むページのHTMLをXHRで取得
- スクレイピングでワンタイムトークンを取得
- 脆弱性のない兄弟サイトBに先程のワンタイムトークンを含むリクエストを送信
とかできちゃうので、結局、「セキュリティ的にワンタイムトークン>セッションIDではない。」のも同じですよ、と。