ソルト付きパスワードハッシュとユーザー認証
このトピックは C# のみではなく、プログラミング全般に関わる内容です。
パスワードは平文で保存してはいけない
ログインなどの認証機構を実装しなければならない場合、どうしても何らかの形でユーザー情報をデータベース等に保存する必要があります。
このときに、もしパスワードを平文でデータベースに保存していたとしたら、どうなるでしょうか。
万が一、悪意のあるユーザーにデータベースに侵入されてしまった場合、パスワードが盗まれシステムに不正にアクセスさてしまいます。
また、パスワードは複数のシステムで使いまわす人も少なくありませんから、そのシステムだけではなく、よそのシステムにも不正にログインされてしまうかもしれません。
このため、パスワードをそのまま保存するのはご法度です。
では、どうしたらよいでしょうか。
ここではパスワードの安全な保管方法の考え方の概要を、簡単に説明します。
ソルト付きのパスワードのハッシュを保存する
まず、パスワードは保存しない、ということが重要です。
パスワードは保存しない。認証するのに十分な情報だけを保存する。さらに、その情報から元のパスワードを推測されないようにする、ということが基本的な考え方です。
ユーザー認証の際にはパスワードをチェックしたいのに、パスワードを保存しない、というのは一見無茶苦茶なことのように思われますが、実は良い方法があります。
パスワードのハッシュを保存すればよいのです。
ハッシュ関数というのは、ある入力 I1 に対していつも同じ結果 R1 を返す関数です。セキュリティを確保するのに使われるハッシュ関数は、入力 I2 が I1 と少しでも違えば、その結果 R2 が R1 と大きく異なるように出来ているようなものです。
このためハッシュの結果 R1 や R2 から I1 や I2 を推測することができません。
「推測することが出来ない」・・・だから、安全、といいたいところですが、実はこれではまだ不十分です。
パスワードになりそうな文字のハッシュを予め用意しておき、それを片っ端からチェックしていけばパスワードが推測されてしまうわけです。
パスワードは人間が画面で入力するのが普通ですから、せいぜい長くても10文字前後です。こうなるとそれぞれに対するハッシュもそれほど多くないことになってしまいます。
そこで、パスワードに "ソルト" と呼ばれるランダムなデータをつけて、そのハッシュをとります。こうすると、同じパスワードに対しても、 全く異なるハッシュ値が保存されることになります。
これによって、ハッシュからパスワードを推測される危険性が格段に減ります。
以上が基本的な考え方です。
この上でよりセキュアにするためには、適切なハッシュ関数を使う、複数回ハッシュをとり総当り攻撃 (ブルート・フォース・アタック) をしにくくする、などの方法が用いられます。
適切なハッシュ関数を使うというのは、明らかですね。極端な話どんな入力に対しても、'ABC' というハッシュを生成するポンコツ関数であれば、 元のパスワードは、まぁ、推測はできないかもしれませんが、ログインを許してしまいます。それはハッシュ関数が不適切であるということです。
後者の複数回ハッシュを計算するというのは、ストレッチングと呼ばれる方法で、ハッシュ値を繰り返し計算することによってハッシュを求める手間を増やすことです。これによって総当り攻撃を行なうための計算量を増大させ安全性を高めます。