2011年8月23日火曜日

PHP5.3.7のcrypt関数に致命的な脆弱性(Bug #55439)

 PHP5.3.7のcrypt関数には致命的な脆弱性があります。最悪のケースでは、任意のパスワードでログインできてしまうという事態が発生します。該当する利用者は、至急、後述する回避策を実施することを推奨します。

概要

PHPのcrypt関数は、ソルト付きハッシュ値を簡単に求めることができます(公式リファレンス)。crypt関数のハッシュアルゴリズムとしてMD5を指定した場合、ソルトのみが出力され、ハッシュ値が空になります。これは、crypt関数の結果がソルトのみに依存し、パスワードには影響されないことを意味し、crypt関数を認証に用いている場合、任意のパスワードでログインに成功する可能性があります。

影響を受けるアプリケーション

crypt関数を用い、ハッシュアルゴリズムとしてMD5を指定しているアプリケーション。
環境にも依存しますが、デフォルトがMD5の場合もあります。筆者のテスト環境(CentOS5.6上のPHP5.1.6およびUbutu 10.04上のPHP5.3.7)では、デフォルトでMD5でした。

解説

crypt関数はパスワードと、省略可能なソルトを引数にとり、ソルトおよびハッシュ値をつなげたものを出力します。
string crypt ( string $str [, string $salt ] )
まず、脆弱性のない正常系を説明するために、一番簡単な呼び出し例を以下に示します。
var_dump(crypt('pass'));
【実行結果】
string(34) "$1$tggeeij6$gtuAR4G2wT9XKWCuLxgcc."
実行結果で、$1$はハッシュアルゴリズムがMD5であること、その次の「tggeeij6」はcrypt関数の内部で生成したソルト、「gtuAR4G2wT9XKWCuLxgcc.」はソルト付きハッシュ値です。ユーザ登録およびパスワード変更の際、上記のように呼び出したcrypt関数の結果をDBに保存します。
認証の際のパスワード照合は以下のようにします。まず、ログイン画面で指定されたユーザに対応するハッシュ値をDBから取り出し、そこから、ハッシュアルゴリズムとソルトまでの部分を切り出します。上記の例では、「$1$tggeeij6」が該当します。次に、利用者の指定したパスワードを用いて、crypt関数を呼び出します。
var_dump(crypt('pass', '$1$tggeeij6'));
【実行結果】
string(34) "$1$tggeeij6$gtuAR4G2wT9XKWCuLxgcc."
この値と、DBに保存されたハッシュ値を比較し、同一であれば認証成功です。上記例では、両者が一致しているので、認証成功になります。
一方、パスワードとして「hoge」が指示された場合を以下に示します。
var_dump(crypt('hoge', '$1$tggeeij6'));
【実行結果】
string(34) "$1$tggeeij6$kCvgMXx7rTKbrciqtQYDs1"
今度は、DBに保存されたものと違う結果になりましたので、認証は失敗と言うことになります。

次に、PHP5.3.7での結果を以下に示します。まず、パスワードのみを指定した場合です。
var_dump(crypt('pass'));
【実行結果】
string(11) "$1$BOF.kMcm"
ご覧のように、ソルトまでの部分しか返っておらず、肝心のハッシュ値がありません。この値をDBに保存したと仮定して、次にユーザが認証時にパスワード「hoge」を指定した場合を以下に示します。
var_dump(crypt('hoge', '$1$BOF.kMcm'));
【実行結果】
string(11) "$1$BOF.kMcm"
パスワードの違いは反映されず、DB上のハッシュ値(実はハッシュは空)とcrypt関数の結果は一致します。認証プログラムの実装にもよりますが、最悪のケースでは「任意のパスワードで認証可能」という状況になります。
データベース上のハッシュ値がPHP5.3.6以前の環境で生成された場合、利用者が正しいパスワードを指定してもログインできないという状況になります。こちらは実装に依存しません。

対策

現在この問題を改修したPHP5.3.8を準備中とのことですが、当面のあいだPHP5.3.6にロールバックすることを推奨します。PHP5.3.8が出た後でも、試験環境などでテストを十分に実施するか、しばらく安定度を確認してからPHP5.3.8に移行することを推奨します。
PHP5.3.6にロールバックするまでの間、あるいはPHP5.3.6にロールバックできない場合、上記に該当するWebアプリケーションは、問題が改修されるまでサービスを停止するべきです。

また、認証用のデータベースを確認して、ハッシュ値が空である利用者がいれば、パスワードのリセットが必要となります。

まとめ

PHP5.3.7のcrypt関数の脆弱性について報告しました。ハッシュアルゴリズムとしてMD5を指定している場合、影響は甚大ですので、サービスを即時停止した上で、PHP5.3.6にロールバックすることを推奨します。

追記

この問題の原因について「PHP5.3.7のcrypt関数のバグはこうして生まれた」にまとめましたのでお読み下さい。

0 件のコメント:

コメントを投稿

フォロワー