[PHP-users 28631] Re: クッキーにメールアドレスを保存するリスク、Session Fixation (was Re: MD5の仕組みについて)

Yasuo Ohgaki yohgaki @ ohgaki.net
2006年 3月 6日 (月) 17:53:39 JST


大垣です。

SATOH Fumiyasu wrote:
> さとうふみやす @ ミラクルです。
> 
> At Sat, 04 Mar 2006 06:41:14 +0900,
> Yasuo Ohgaki wrote:
>>> echo md5('メールアドレス'+'何か');
>> 上記は良くない例の一つになります。一部にでも予測可能な文字列は含まない
>> よういするべきです。prefix程度ならまだ良いですがメールアドレスやアカウ
>> ント名などのは絶対に含めてはならない情報です。
> 
> MD5 の種に予測不可能な文字列 ('何か'?) が含まれているなら、
> 予測可能な文字列 ('メールアドレス') が含まれていても
> 問題ないと思いますが、いかがでしょうか。

セキュリティ対策のベストプラクティスとしては

- 露出の必要がない情報、特に個人情報は一部でも外部に露出させない

は重要です。メールアドレスやユーザIDはシステムが正しく動作する為にブ
ラウザに送信しなくてもよい情報です。たとえセッションクッキーであった
としてもユーザのメールアドレスが含まれるようなクッキーを設定するべき
ではないです。

もちろん、

>>> echo md5('メールアドレス'+'何か');

システム的に期待通りに動作するか?という意味では問題は無く動作はします。


数十人のプログラマがいるとして、クッキーに保存する情報のセキュリティ
ポリシーとしては

- 予測不能なランダム文字列
- 一度に表示するレコード数などの表示設定

に限定するはずです。

- セキュリティ上問題が無ければメール・ユーザ名を含むクッキーもOK

とするようなセキュリティポリシーは普通は作りません。

例えば、共有PCではメールアドレスがクッキーとして保存されるのは*現実的*な
セキュリティ上のリスクといえます。

色々な悪用方法が考えられると思いますが、Phishingには利用しやすいでしょう。
メールアドレスが判り、クッキーの有効期限等からPCを利用していた時間も判りま
す。サイトのアドレスもわかっているので、スピアフィッシングには最適な情報
です。



>>> であればメールアドレスがユニークである限り
>>> ユニークの文字列となるのでしょうか?
>> 確立的にはユニークであるという前提で普通は問題ないです。
> 
> 個人的には、競合する可能性があるのにそれを放置するのは、
> 問題 (バグ)だと思う。
> 
>>> 過去ログを拝見しますと、md5は無限の事象を有限の長さに写すとあるので、
>>> ユニークになるとは限らず生成した後に重複チェックをしないと
>>> ユーザー毎に一意とすることはできないでしょうか?
>> 確立的には必要と思われていません。
> 
> あまり多くの実装を見てきたわけではありませんが、
> 残念ながらそういったものばかりのようです。うーん…。
> 
>>> PHPのセッションIDも生成時に重複チェックをしているのでしょうか?
>> していません。
> 
> バグだと思うんだけどなぁ。マニュアルなどに重複する可能性が
> 記載されているなら、仕様 (制限事項) かな。
> 

MD5レベルでも値のコリージョンを検出しているケースはあまり無いと思います。
しかし、もし私がメンテナならいちいち議論するのも面倒ですし、検出すれば
コリージョンは絶対に発生しないので検出するようにしてしまうと思います。

# n/2^128の確立でのコリージョンが許されないようなシステムではコリージョ
# ン検出をすることも可能です。nはその時点で有効なセッションの数。
# 実際にはn/2^128よりもコリージョン確立は高いですが、確率的には無視でき
# ます。(と確立・統計では習った)例えば、どんなに強固な暗号でもブルート
# フォースで100%解読できます。しかし、確率的に解読できるまでに十分な時間
# が必要な場合は信頼できると考えられれています。これと同じです。この前提
# が無効ならTLS/SSLによるセキュリティも無効です。
# 普通、コリージョンは現実的なリスクとは考えられていません。しかし、銀行
# などのシステムなら私もコリージョンの検出は行います。検出は簡単なので。

現状のPHPでも、自前でセッションセーブハンドラを定義すれば、コリージョ
ンを検出できます。

//セッションを初期化する前
if (セッションIDとなるクッキーが設定されている) {
 // session fixation対策
 if (セッションIDはあるがそのIDでセッションは初期化されていない) {
  do {
     セッションIDを生成
  } while (生成したセッションIDが有効なセッションIDである)
   生成したセッションIDでセッションを開始
  } else {
    送信されたセッションIDでセッションを開始
  }
} else {
 do {
    セッションIDを生成
 } while (生成したセッションIDが有効なセッションIDである)
  生成したセッションIDでセッションを開始
}

と言った感じでコリージョンの可能性を排除したセッション管理を実装できます。
この例ではついでにsession fixation攻撃にも対処しています。私は実際に上記のような
仕組みを持つセーブハンドラも使用しています。

ところで、PHPのセッション管理には危険なセキュリティ上の問題、session fixation、
があります。

http://blog.ohgaki.net/index.php/yohgaki/2006/02/05/phpa_rsession_fixationa_ei
http://blog.ohgaki.net/index.php/yohgaki/2006/03/03/phpa_rstricta_ra_a_ma_sa_s

こちらの対策前にコリージョン対策を行っても意味がありません。
個人的にはこの危険性を何年も前から機会があると話しています。しかし、認知度は今ひ
とつ低いようです...

-- 
Yasuo Ohgaki





PHP-users メーリングリストの案内