サーバーを自由に弄れない環境でのセッションID生成 ― 2006年06月20日 10時50分51秒
あらまし
頼まれ仕事なのですが、こんな感じの Web スペース上で、「管理者だけが閲覧できるページ」を含む Web アプリを実現せなあかんちうことになりまして、もちろん基本認証とかも使えないので、CGI だけで認証機構を用意しないといけないのですが、その実現方法をどうしようかなぁというお話。
実は、既にプログラムは Perl で途中まで組まれていて、認証機構の実現で幾分か行き詰っている状態なのであります。重要なのは、信頼性の高いハッシュ関数と、暗号理論上安全な乱数の生成であり、これらは Perl の場合、前者は Digest::SHA
かもしくは MD5
、後者は Math::TrulyRandom
といったモジュールを追加してあげれば確実に実現可能なわけですが、自分で設定できるサーバーを使うわけではないため、これらのモジュールを組み込んで使うことは不可能だったりするわけです。
gcc をサポート、とあるので、各モジュールのソースをダウンロードして make まではできるのかもしれないけどね。それができれば CGI プログラムと同じ場所においておくことでとりあえず動かすことはできるけど。。。そもそも telnet や ssh が使えるわけでもないのにどうやって make を走らせるんだろう?
んで、一体どうしたもんかなぁという辺りをぐだぐだと考えてみるテストなのです。
ハッシュ関数
PHP3 が使えるので、PHP の md5()
関数を使うという手がある。Perl から PHP の関数を利用するには、例えばこんな風に書けばいいんじゃないかな。
my $digest = `php -r 'echo md5("$text");'`;
むしろプログラム自体を PHP で書け、という話もあるのですが。。。まぁ拡張子を「.php3
」にすれば確かに PHP3 環境のテストもできるけどさぁ。
PHP を外から使うのがまどろっこしいと思うのであれば、あとは crypt
関数を利用する、という手もある。この手の無料 Web スペースや安価なレンサバなんかの場合、OS は大概 Linux だろうと思われるので、crypt
がサポートする暗号方式もおそらく 64 bits DES 方式かと思われる。その場合、ハッシュ化できる文字列は最大 8 文字までなので、crypt
関数自体を複数回に分けで呼び出してあげる必要があると思う。あーマンドクセ('A`)
乱数
セッション ID を生成する基本的なやり方は、状況を識別できる情報 (ユーザー ID、時刻、その他必要に応じてシチュエーションを識別する記号) と、暗号理論上安全な乱数とを混ぜ合わせた文字列*1を、ハッシュ関数によって符号化*2する、というもの。十分に識別可能であり、また、十分に予測不可能であることが必要とされるわけです。
で、その肝心の乱数ですが、仮にサーバーの OS が Linux ならば、/dev/random
や /dev/urandom
を使用することができます。例えば Perl で 64 bits (= 8 Bytes) の乱数列を得るには、以下のように記述することになります。
my $text; open randin, "</dev/random" or die 'Cannot use /dev/random'; read randin, $text, 8; close randin;
Manpage を見ると、/dev/random
はより安全だが、エントロピー・プールが空になるとブロックされてしまう、とある。実際に使ってみると分かるのだが、キーボードやマウスからの入力がないと、数バイト読み出しただけで処理はブロックされてしまう。ホスティングサーバーなどはヒューマン・インタフェースが接続すらされていない可能性が高いため、これでは使い物にならない。かといって、/dev/urandom
では、ブロックはされないが、環境ノイズが十分に反映されない可能性があるため、決して安全であるとはいえないかもしれない。
ちなみに、PHP には mt_rand()
という関数があり、普通に rand() 関数とか使うよりはマシっぽそうに見えるのだが、これが採用している擬似乱数生成法である Mersenne Twister は 暗号論的な擬似乱数ではないため、これだけでは安全ではない。でも Mersenne Twister の公式サイトには 従来存在した「線形疑似乱数(LFSRなど)プラスSHA」の 線形擬似乱数の代わりに MT を使うことは有効
なんて書かれてるんだよなぁ。。。いくら非可逆圧縮かましたところで、予測可能な数列であることに変わりはないと思うんだけどなぁ。
最近のコメント