php のセッションID と エントロピーソース

php のセッションID についてのお話。
php5 以降、セッションID の生成アルゴリズムを設定値によって、ある程度制御できるようになっています。

session.entropy_file
ベースに利用される乱数(IPアドレス, 現在時刻, 線形合同法による疑似乱数 を組み合わせたもの)に追加して、乱数発生源とするファイル。 default:''(空文字)
session.entropy_length
entropy_file から読み取るバイト数。 default:0
session.hash_function
ハッシュアルゴリズムを指定。0:md5(128bit) 1:sha1(160bit) php5.3 以降は hash モジュールの各種アルゴリズムを指定することが可能 default:0
session.hash_bits_per_character
生成されたハッシュ(バイナリ)を文字列に変換する際に、何bit ずつパックするか。 4: 4bit(16進数:0-9 a-f), 5: 5bit(32進数:0-9 a-v), 6: 6bit(64進数:0-9 a-z A-Z "-" ",") default:4


当然セッションID ってのは、別の人に対して同じ値が作られちゃいけません。
また、類推できる値でもイケナイので、一意性とランダムさが重要なわけです。

ところが、php のデフォルト設定では、 IPアドレス, 現在時刻, 線形合同法による疑似乱数 を md5 して16進文字列 が利用されます。

ある程度の規模ならば問題ないのでしょうが、複数台のサーバで php を動かすような規模になってくると、これだけのエントロピーソースでは不安になります。

高木氏にもはてブコメント

[セキュリティ][乱数][暗号][PHP][moderate] PHPはセッションID生成にsecureな擬似乱数生成系を使用していないようだ。さすがPHPらしい駄目っぷり。

なんて言われてるし。

そこで session.entropy_file の出番です。

session.entropy_file でファイルを指定すると、php はこのファイルから session.entropy_length バイト分読み込み、それもエントロピーソースとして利用してくれるようになります。

で、この session.entropy_file に指定するファイルですが、マニュアルにも載っているとおり、 /dev/random や /dev/urandom を利用するのがいいのかもしれませんが、
Linux の /dev/random はロックする危険性があるし、/dev/urandom を利用したところで、他の /dev/random を利用するアプリケーションの邪魔をしてしまいます。

(乱数発生器のエントロピーを増やす方法がいまいちよくわからないし。)

って思っていたら、 Ethna では /proc/net/dev を利用していました。(session.entropy_file ではなく、 Ethna 内でセッションID を生成する課程で利用しています)
/proc/net/dev は、ネットワーク統計を得るファイルですね。

確かにこれなら、時々刻々と変わる上に、/dev/random のような心配もいらないのでいいかも。
と思って利用しています。

session.entropy_length は 2048。
ソースコード上、whileループの1回分で読み込む最大量にしてます。(ext/session/session.c@420 / php5.3.1)

今のところ問題起きてないみたい。