2009.01.27 Tuesday
注意
こないだこんなエントリを書いた。ブログが続かないわけ | [PHP]パスワードのハッシュ化にはcrypt が便利
そこそこ見てくれた人もいるし、ブックマークもいくつかついている。
そういう状況で非常にいいにくいのだが、これは間違いだ。
ごめんなさい。
パスワード周りの話で、セキュリティ上も重要なのでしっかりと訂正しておく。
crypt をパスワードのハッシュ化に使ってはいけない!
そのシステム内でどんな暗号化方式を使っているかわからないが、それがDESベースであれば、もう致命的だ。システム内の暗号化方式を調べてまでcrypt を使うメリットはなく、そんなことをするくらいなら、頑張ってsalt を生成させて、それからsha1 などで暗号化する方がよっぽどマシである。もう一度言う。
crypt をパスワードのハッシュ化に使ってはいけない!
なぜか
PHP: crypt - Manual定義: string crypt ( string $str [, string $salt ] )要は、8文字を越える部分はパスワードとして意味を持たず、最初の8文字だけで比較されるということだ。例えば、下記のパスワードは全て同じとみなされ、認証も通ってしまう。
標準の DES ベースの暗号化の場合、crypt() は出力の最初の 2 文字を salt として使用します。また、 str の最初の 8 文字しか使用しません。 つまり、最初の 8 文字が同じである長い文字列は、 同じ salt を使う限り同じ結果となります。
mypassword
mypasswond
mypassworddesuyo
mypasswo tte tsuiterya nandemo iiyo.
先ほどのPHP マニュアルにある「例1 crypt() の例」というのがもう最悪。
$password = crypt('mypassword'); // saltを自動的に生成させます
/* 異なったハッシュアルゴリズムが使用された際の問題を避けるために
crypt()の結果全体をパスワード比較用のsaltとして渡す必要があります。
(上記のように標準DESに基づくパスワードハッシュは2文字のsaltを使用します
が、MD5に基づくハッシュは12文字のsaltを使用します) */
if (crypt($user_input, $password) == $password) {
echo "Password verified!";
}
?>あたかも、パスワードのハッシュ化の正攻法に見える。ところが、先ほど説明した通り、DESベースの場合、mypasswoしか有効にならない。このサンプルを少し書き換えて、$user_input に値を与えて確かめてみる。
$password = crypt('mypassword'); // saltを自動的に生成させます
/* 異なったハッシュアルゴリズムが使用された際の問題を避けるために
crypt()の結果全体をパスワード比較用のsaltとして渡す必要があります。
(上記のように標準DESに基づくパスワードハッシュは2文字のsaltを使用します
が、MD5に基づくハッシュは12文字のsaltを使用します) */
$use_input = "mypassword toha chigaimasuyo";
if (crypt($user_input, $password) == $password) {
echo "Password verified!";
}
?>$user_input に「mypassword toha chigaimasuyo」という、最初の8文字は同じだけどあとはでたらめのパスワードを与えてみる。結果は、
Password verified!「Password verified!」じゃねぇよ!
やっぱり、パスワードのハッシュ化はsha1 などが王道になるのだろうか。
例)
$password = 'mypassword';salt の生成にcrypt を使ってみた。
$salt = crypt($pass);
$pass_hash = sha1($salt . $pass);
それにしても、PHPマニュアルにはなんであんなサンプルが載っているんだろ?
パスワードはなるべく強固にと言われているこのご時世で、パスワードは8文字以内とか制限付けるのもバカらしいし。
では、最後にもう一度。
crypt をパスワードのハッシュ化に使ってはいけない!