CSRF対策の実際 - PHPプロ!Q&A掲示板

3140

  • 0P

CSRF対策の実際

質問日時 / 2011年3月4日 23:17    回答数 / 5件

Questioner:  meron  このエントリーをはてなブックマークに追加 

キーワード / キーワードが設定されていません

CSRF対策について調べていますが、情報が錯綜しており実際にどのように
すればいいのかわかりかねています。

1. CSRF対策には固定トークン、ワンタイムトークンを使用する方法など
   様々な対策がありますが実際の現場ではどのように対策されているのか。

2. 肝心のトークンは日付やsession_id等、何を元に生成するか。

3. それを元に、md5sha1、それより強い暗号化強度を持つハッシュ関数を
   使用して生成するのか。

以上の三点が疑問なのですが、よろしくお願いします。

この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。



ツリー一覧

┣A01ockeghem1.現場ではさまざまな方法で対策されていますが、間違
┗A02Kanonbell# 徳丸さんかな?徳丸さんだよね? # ブログその他の
 ┗A02-1meronockeghemさん、ありがとうございます。 >PHPの場合
  ┗A02-1-1Kanonbell>どうすれば推測が非常に困難な文字列を生成できるの
   ┗A02-1-1-1meronセッションIDは信用できるという事なので、こちらを基

回答一覧

並び替え:

A01
answererockeghem [3月7日 09:20]

1.現場ではさまざまな方法で対策されていますが、間違った方法も珍しくありません
2.トークンの要件は、「第三者に推定されないこと」です。ワンタイムである必要はありません。PHPの場合、身近な「第三者に推定されない」トークンとしてセッションID(session_id)があります。仮にこれが推定されると、簡単にセッションハイジャックされるので、CSRF以上の影響が出ます。このため、セッションID(session_id)は推定されない(ように対策されている)という前提をおくことができます
3.トークンとして推測の困難なものを使っている場合、それに加えてハッシュ関数を通す必要はありません

この意見に回答する

ツリーへ TOPへ

A02
answererKanonbell [3月7日 20:13]

# 徳丸さんかな?徳丸さんだよね?
# ブログその他の記事では大変勉強させていただいています。

CSRFについては、そもそも母数となる情報が少ない気もしますね。
罠を張ってじっと待つタイプの受動的な攻撃なので、成功すれば強力であっても実例があまりないために、盛り上がらないのでしょうか。

まずはじめに、CSRF対策について言及された有力な記事をご紹介しておきます。
検索すれば上位に出てくるので、すでにご存知かなとは思いますが。
「開発者のための正しいCSRF対策」
http://www.jumperz.net/texts/csrf.htm
「高木浩光@自宅の日記」
http://takagi-hiromitsu.jp/diary/20050427.html
「徳丸浩の日記」(CSRFの日記もトップ以外にあったと思うけどどこだろ・・・)
http://www.tokumaru.org/d/
「yohgaki's blog」(CSRFの日記あったと思うけどどこだっけ?)
http://blog.ohgaki.net/

徳丸氏と大垣氏はIT系サイトや書籍でもよく情報を発信していらっしゃいます。


# CSRFで検索すると@ITの記事も引っかかるのですが、紹介しません。


1.固定もワンタイムも両方使われていると思います。要件や環境によると言えるでしょうか。
フレームワークでトランザクショントークンを用意している場合はほとんど何も考えずにそのまま使えたりするので、よく知らない人もいるかもしれませんね。

私自身はワンタイムトークンです。CSRF対策としてはどちらでも構わないものの、複数ウィンドウでの操作が出来なくなるという点で致命的と考えているので、固定トークンを使うことはありません。

2.タイムリーなことに、日付を種に生成したワンタイムトークンの脆弱性について言及があります。
ご本人がいらっしゃいますが。。。
http://www.tokumaru.org/d/20110127.html
しかしこんなに短時間で突破されるとは、と言う感じです。頭で思うよりはるかに脆弱ですね。


「開発者のための正しいCSRF対策」では固定トークンにセッションIDを使うべきではないとされていますが、「高木浩光@自宅の日記」ではこの主張に対して反論されています。

どっちの主張に従えばいいのかは両方を見てご自身で判断していただきたいところですが、固定トークンであればセッションIDで構わないと思います。
そこに不安を感じるのであれば、sha1とか使って生のセッションIDを避けても良いでしょう(オマジナイですらありませんが)。
ワンタイムトークンであればセッションIDに匹敵する、推測が非常に困難なIDを自前で用意することになります。
ぶっちゃけセッションID+他の何か(時刻でもuniqueidでも)で良い気がしますけれど。
セッションID自体は、推測が非常に困難(実質的に不可能)であると規定されているので。

それ以外の何かを使いたい場合は、「/dev/urandom」あたりをキーワードに旅をしてみるのもいいかもしれません。英語の壁を越える必要はありそうですが、貴方の血肉になる何かを得ることは出来るでしょう。
PHP公式のrand()やmt_rand()のコメント欄でも、若干の言及があります。

3.2で語ってしまいましたが、「推測が非常に困難」な文字列を生成してしまえば、ハッシュ関数を使う必要はありません。
誰でも思いつくような簡単なパスワード使っちゃうと、どんなに頑強な暗号で守ろうがあっさり破られちゃうでしょ?って話で。

攻撃する側も、種にハッシュ関数かけてるかもくらいは想像するので、例えば辞書攻撃だったら辞書内容+ハッシュ関数かけた内容くらいは試行します。
推測されうる時点でアウトであり、SSLのような事情と違って経路の保護が不要なのでハッシュとかはいらないです。

いや、なんとなくかけちゃうんですけどね。

種をあまり工夫しない代わりに、saltなどをまぶしつつsha1を使えばある程度は推測しづらい文字列が出来るかもしれませんが。。。
「実質的に推測不可能と言えるくらい推測が困難」という定義の話になるととても難しい暗号関連の話になってくるので、その定義を十分(またはある程度)満たしているのかどうか、つまり脆弱ではないのかどうか客観的に判断するのが難しくなります。
難しいことは他人に考えてもらった方が良いので、 「実質的に推測不可能と言えるくらい推測が困難」とされているものを拾ってくるようにしましょう。


CSRF対策のためにトランザクショントークンを導入すると、よくある多重更新防止の仕組みも導入できてしまいます。
また、画面遷移をある程度設計者の意図通りに強制することもできたりするんですが、あまり盛り上がりを感じない分野ですね~。
私は複数ウィンドウを許容する場合のワンタイムトークンの実装例を探してみたんですが、ちっとも見当たらなかったです。
攻撃の成功要件が非常に厳しい上、そもそも理解しにくいのが原因でしょうか。
上二つの理由もあって、要求されるセキュリティの要件が大したことなくても、実装すべきだと私は思うんですけどね。

この意見に回答する

ツリーへ TOPへ

A02-1
replyermeron [3月7日 22:58]

ockeghemさん、ありがとうございます。

>PHPの場合、身近な「第三者に推定されない」トークンとしてセッションID(session_id)があります。仮にこれが推定されると、簡単にセッションハイジャックされるので、CSRF以上の影響が出ます。このため、セッションID(session_id)は推定されない(ように対策
されている)という前提をおくことができます

セッションIDは安全と考えて良いという事ですね。

>3.トークンとして推測の困難なものを使っている場合、それに加えてハッシュ関数を通す必要はありません

確かにその通りですね。

Kanonbellさん、詳しい解説ありがとうざいます。
知りたかった情報が網羅されており、理解できました。

>CSRFについては、そもそも母数となる情報が少ない気もしますね。
罠を張ってじっと待つタイプの受動的な攻撃なので、成功すれば強力であっても実例があまりないために、盛り上がらないのでしょうか。

やはり多いのはSQLインジェクションやクロサイトスクリプティングになるんでしょうか。

>推測されうる時点でアウトであり、SSLのような事情と違って経路の保護が不要なのでハッシュとかはいらないです。

>いや、なんとなくかけちゃうんですけどね。

なんとなくわかります。

>それ以外の何かを使いたい場合は、「/dev/urandom」あたりをキーワードに旅をしてみるのもいいかもしれません。

これについてはサっと目を通しただけでしたが、もう少し深く調べてみる事にします。

>3.2で語ってしまいましたが、「推測が非常に困難」な文字列を生成してしまえば、ハッシュ関数を使う必要はありません。

これについてはどうすれば推測が非常に困難な文字列を生成できるのか、皆目見当がつきません。

この意見に回答する

ツリーへ TOPへ

A02-1-1 満足
replyerKanonbell [3月8日 00:38]

>どうすれば推測が非常に困難な文字列を生成できるのか、皆目見当がつきません。

非常に身近なもので言えば、セッションIDがそうです。
Webで使用されるどの言語や処理系でもセッションIDが普通用意されていますが、この要件を満たすように作られています。
※過去のPHPではこの要件を満たさないバグがありましたけれど。

なので、セッションIDをそのまま使うか、これを材料にちょっと細工をして使うのであれば、やはり推測が非常に困難な文字列と言えるでしょう。
難しいことは他人に考えてもらうってのはそういうことです。
※もちろんセッションIDの文字列を短くして使ったりしたらダメです。

もうちょっと自前で頑張ろうとする場合は、PHPや他の言語・処理系がどのようにセッションIDを生成しているかを調べてみると良いでしょう。
「/dev/urandom」のほか、「(擬似)乱数生成機」というキーワードも参考になるでしょうか。
まあその前に、「現実的に推測不可能と言えるほどに推測が困難な文字列」の定義をまず調べる必要があるんですけどね。
じゃないとせっかく生成した文字列があっさり破られる程度なのかもしれないし、むしろ長すぎて無駄なのかもい知れないし。
昔SSLだかセッションIDだかの勉強してる時に証明付きで見た記憶があるんですが、もう忘れちゃいました。

まあ、この辺りを掘っていくと非常にアカデミックかつ抽象的になり、現場レベルからは遠ざかっていきます。
現実的に出来る努力は、セッションIDの生成方法を調べる辺りでしょうかね。
↓こういうところも参考にしてみてください。
http://blog.ohgaki.net/php-python

この意見に回答する

ツリーへ TOPへ

A02-1-1-1
replyermeron [3月8日 17:43]

セッションIDは信用できるという事なので、こちらを基本として
対策していきたいと思います。

>「/dev/urandom」のほか、「(擬似)乱数生成機」というキーワードも参考になるでしょうか。

こちらも勉強してみたいと思います。
お二人ともありがとうざいました。

この意見に回答する

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
ログファイルの中の空のデータ行を削除したい
 このエントリーをはてなブックマークに追加 
A
ログのデータ個数(列数)が固定で、空のログが"<><><>"だと既知であれば if ($line === "<><><>") { continue; } で読み飛ばしてもいいのでは? ...

>>続きを読む

まずは配列や文字列の扱いから、じっくり勉強して行きましょう。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)