皆さん、こんにちは!
この記事でログインについて書きましたが。。
今回はその深堀をしたいと思います。
というもの自分の中で、パスワードのハッシュについて整理できていない点がありましたので、ここでまとめておきます!
Hash(ハッシュ)とはなにか?
そもそも、Hashとはなにかということからなんですが。。。
ある文字列から作りだされる一意な文字列のことです。
ある文字列AをHash関数にいれると、その文字列Aに対応した文字列が返されます。
一意なという意味は、同じ文字列をHash関数にいれると結果は同じ文字列になります。
例えば、
- 文字列「AAA」をあるHash関数に与えると、必ず文字列「xxxxA」が返ってくる。
- 文字列「BBB」をあるHash関数に与えると、必ず文字列「xxxxB」が返ってくる。
といった感じです。
パスワードをHash化する理由は?
次に、なぜパスワードをHash化するのかなんですが。
これは万が一DBのデータが流出した場合にも、悪意のある第三者が他人になりすましてログインするのを防ぐためです。
パスワード自体が平文でHash化されていないことを想定すると、DBのデータをみればすぐにパスワードがわかってしまいます。
しかし、パスワードがHash化されている場合、一目みただけでは、そのパスワードがなんなのかわかりません。
ということもあり、ログイン認証で使用するパスワードは必ずHash化されて保存するべきものです。
Hash化と暗号化は異なる?
ここまで読んだ方の中で、Hash化と暗号化はどう違うのかと気になった人もいるのではないかと思い、説明を追加しておきます。
答えは、異なります。
Hash関数というのは、一方向性しかないです。
つまり、ある文字列をHash化したら、そのHash化した文字列は元の文字列には戻せません。
他方、暗号化というのは、暗号化したものを複合化して元の文字列に戻すことができます。
どのHashアルゴリズムを使用するのが一番よいのか
ここではDBに保存するパスワードをHash化するにはどのHashアルゴリズムが良いのかといった観点で考えてみます。
一番重要なことは、他の第三者にそのHash化されたパスワードがわたってしまっても、彼らがログインすることを可能な限り難しくするということです。
つまりどういうことかというと、Hash化された文字列から元のパスワードを導けなくすればOKです。
別の言葉でいうならば、計算によって元のパスワードを求めることが難しければよいわけです。
上のことから、元のパスワードを求めるのに計算量が多くなるアルゴリズムを選択すれば、その第三者が元のパスワードを取得することはほぼ不可能になるので、そうします。
具体的には、bcryptでHash化しておくのがよいとのことです。
ほとんどのケースでbcryptが使用されているのではないでしょうか。
前回のfastapiのログイン実装でもbcryptを使用してます。
また、一回あたりの認証にかかる時間もサービスに影響がないくらいに時間がかかるものを選ぶべきとのこと(※)です。
※Hash関数のアルゴリズムで計算速度が早すぎるものを選択してしまうと、ブルートフォース攻撃を受けた際に早くレスポンスを返してしまうため、それを防ぐためといった理由がある。