パスワードに数字だけがダメな理由

頭の中ではダメだとわかっていたけど・・・

なんでやっちゃいけないか体ではわかっていたけど、具体的にどうしてダメなのかというものが整理できていなかったので、
J●Lのパスワード問題が盛り上がった後のこの際なのでまとめておきます。

パスワードの総当たり確認が実はすごい簡単に出来てしまう記事
http://z.tokumaru.org/2014/02/6php025.html
http://qiita.com/kawasima/items/ef75f317605ce800a839

物騒な話なのでパスワード問い合わせシステムと申しておりますが、あっさりと1秒もかからずに何万件と処理できています。

そもそもなんでダメなのか

そもそもパスワードをDBに保存する場合には、
もしかして盗まれても相手にパスワードがわからないように暗号化してから保存する手段をとります。

暗号化する手段をハッシュ値をとるとか言います。

ハッシュとは

ハッシュ関数とは
不可逆な一方向関数を含むため、ハッシュ値から原文を再現することはできず、また同じハッシュ値を持つ異なるデータを作成することは極めて困難である。通信の暗号化の補助や、ユーザ認証やデジタル署名などに応用されている。

http://e-words.jp/w/E3838FE38383E382B7E383A5E996A2E695B0.html

ある文字列や数字からハッシュ値を導くと元の数字に戻すのはほぼ不可能なので、
パスワードをハッシュ値に変換したものをDBに保存しておいて、入力されたパスワードに対して同じハッシュ値を導いて比較を行う方法をハッシュ法と言います。

数字だけとか簡単な文字列の何が危ないのかしら?

とりあえず0埋めで数字足し込んでいってハッシュ関数を作って処理してみる。

<?php
$start = microtime(true);
$password = hash('sha256', '999999');

for ($i = 0; $i < 1000000; $i++)
{
    $hash = hash('sha256', sprintf("%06d", $i));

    if ( $password == $hash )
    {
        echo 'match!!' . "\n";
    }
}
echo microtime(true) - $start . "\n";

/*
match!!
result_time = 1.564945936203
*/

100万回繰り返したにもかかわらず2秒かかわらず処理が終わっています。
ハッシュ関数がわかっていてランダムな数字や文字列を延々と読み込ませることができれば、
もしかして対象のハッシュ値と一致するかもしれない・・・
ましてや数字だけのパスワードだとforで回すとカウントアップしながら簡単に総当たりに
調べることができるので色々まずいというわけです。

ハッシュ値がわかってもわからなくする手法

文字を無限に投入できると考えた場合には、
いずれハッシュされた値にもしかして一致する可能性があるので、
ハッシュ関数を複数回行う、
salt値と呼ばれる文字を含んだ状態でハッシュ化するなどなど、
なんにせよ元の文字を直でハッシュ化しないことが地道な対策になります。

体系的に学ぶ 安全なWebアプリケーションの作り方」の総当たり攻撃の部分を勉強するとよろしいかと思われます。