自主的20%るぅる

各々が自主的に好き勝手書くゆるふわ会社ブログ

ハッシュ化・ハッシュ値ってなんだ?から、パスワードの仕組みまで。

こんにちは、江嵜です。

皆さん、ハッシュ値という言葉、聞いたことがありますか?
少し昔の話ですが、 PlayStation Network (PSN) の個人情報が流出した事件の際に、
「パスワードはハッシュ化されて保存されていた」とか、
なんかそんな話聞いたことありますよね?

このハッシュ化・ハッシュ値というもの、IT のセキュリティの世界ではよく使われるのですが、
具体的にどんなものなのか知らない方もいらっしゃるかと思います。

ということで、今回はこのハッシュ値について、理解していきましょう!
(ハッシュタグとかハッシュドビーフとかはあんまり関係ないです!)

ハッシュとは?というところからはじめて、最後には実際に Web サービスでパスワードがどう管理されているかについてまで見ていきますよ!

ハッシュ化とかハッシュ値ってなんぞや?

ハッシュ化…それは要約すること!

ハッシュ化ってなんだ?という問いに一言で答えるとすれば、「要約すること」と言えるでしょう。

要約と言っても、読書感想文みたいな事ではなくて、
文字を一定のルールに従って変換するのです。

例えば “HelloWorld” という文字をハッシュ化してみましょう。

ハッシュ化するには、そのルールが必要になります。
例えば、今回は文字の長さで要約することとしてみます。

HelloWorld は 10 文字ですから、このルールでは HelloWorld をハッシュ化すると 10 という結果が得られることになります。

この時、 HelloWorld を 10 という結果に変換することをハッシュ化
ハッシュ化で生まれた値 10 がハッシュ値と呼ばれるのですね。

そして、ハッシュ化するときのルール、今回は文字の長さを取り出す、というものでしたが、
これをハッシュ関数と呼びます。

ハッシュ化で最も重要なことは同一性!

ハッシュ化した結果は、そのルールによっては数字になるかもしれませんし、
パッと見意味のない文字の羅列になるかもしれません。記号が入っているかもしれません。
その辺りはルール次第なので、結果がどんな形式になっても良いのです。

ただし、守らなければならない決まりもあります。
ハッシュ化する上で最も大切な決まりは、同じ文字をハッシュしたら同じ結果になること、です。

先程の例で考えると、 HelloWorld は何度文字数を数えても 10 文字ですから、
ハッシュ化した結果は必ず 10 になります。
9 や 11 にはならないですよね。

しかし、ハッシュ化のルールをたとえば、「キーボードで打ち込むのにかかる秒数」としたらどうでしょうか?

人によっては 3 秒程度かもしれませんし、 10 秒かかる人だっているでしょう。

ある人がハッシュ化すると 3 だけど、別の人が同じ文字をハッシュ化したら 10 になる、
というルールはハッシュ関数として成立しません。
(それはランダムに数字を生み出しているのと同じですよね!)

必ずハッシュ関数は、誰がどうやっても同じになるルールになっている必要があるのです。

暗号化とハッシュ化の違い…それは元に戻せるかどうか

ちなみに、 IT の世界には「暗号化」という物がありますね。
暗号化も一定のルールに従って文字を変換するものですので、ハッシュ化と暗号化は混同されやすいものです。
(ハッシュ化も暗号化も、パスワードの管理に使われることがありますし!)

ハッシュ化と暗号化の明確な違い、それは元に戻せるかどうか、です。

暗号化は元の文字をそのままでは読めないように変換しますが、
「復号化」という処理をして元の文字に戻せるようになっています。

一方ハッシュ化はどうでしょうか。
先程の例では HelloWorld は 10 という値に変換されました。
HelloWorld を変換したら 10 になるのは分かりますが、
10 という値だけをみて、元の文字が HelloWorld だったという事は分かるでしょうか?
もちろん、わかりませんよね!
もしかしたら GoodNight! だったかもしれませんし、 ABCDEFGHIJ だったかもしれません。
(どれも長さは 10 ですよね!)

パスワードとハッシュの深ーい関係

パスワードはハッシュ化して保存するのが定石!

さて、ここまでハッシュってなんぞや?についてみてきました。
そろそろパスワードとハッシュの関係について、見ていきましょう。

皆さんも日ごろから twitter やら facebook やらと、 Web サービスを色々と使っているかと思います。
大体の Web サービスでは、最初に会員登録をしますよね。
その時に、パスワードの入力を求められるかと思います。

そのパスワードは大抵の場合データベースに保管されます。
そして、後日ログインする際に再度パスワードを入力してもらい、データベースに保管されているパスワードと一致したら、本人がアクセスしてきたのだと判断するのですね。

そんなパスワードですが、これはとても大切な個人情報ですよね。
(パスワードがばれてしまえば、他人があなたになりすましできるのですから!)

大切なパスワードですが、データベースにはどのように保管されているかご存知でしょうか。

データベースそのものに強固なセキュリティをかけたり、不審なアクセスを通さないようにすることももちろん大切です。
しかし、パスワードを盗もうとする側も日々進歩しています。
どうしても防ぎきれず、データベースの情報が漏れてしまうことはあります。
また、もしかしたらデータベースにアクセスできる、内部の人間が盗む可能性だってありますよね。

そういった事態に備えて、大抵の Web サービスではどのようにしてパスワードを管理しているかというと…
パスワードをハッシュ化して、データベースに保管しているのですね!

ハッシュ化して保存しておくと、データベースの情報が漏れたとしても、
設定されているパスワードそのものが何だったかは分からない、
ということで、漏れてもすぐに問題にはなりにくい、ということですね。

何で暗号化じゃダメなの?

ここで皆さん、もしかしたらこう考えられたかもしれません。

「パスワードはハッシュ化じゃなくて、暗号化して保存してもいいんじゃない?
漏れたときにパスワードが分からなければいいんでしょ?」と。

いいご質問ですね!

実は、暗号化ではなくハッシュ化を使用しているのには、きちんと理由があるのです。

確かに、漏れたときにパスワードそのものが漏れないのは、暗号化でもハッシュ化でも同じです。

しかし、考えてみてください。
暗号化したものは「復号化」で戻せるんでしたよね。

例えば、復号化に必要な鍵も一緒に漏れてしまっていたとしたら…
例えば、データベースから情報を盗んだのが、鍵を使える内部の人間だったとしたら…

そう、復号化して元のパスワードが何だったのかが分かってしまいますよね。

パスワードをハッシュ化して保管するのは、どうやっても元のパスワードが分からないようにするためなのです。

ちょっと待って!それじゃあログインも出来ないんじゃないの?

ここまで来て、皆さんは違和感を覚えたかもしれません。

「確かに、ハッシュ化は元に戻せないから安全だって分かったよ。
けど、元に戻せないんじゃあ、後日パスワードを持っている人がログインしたときに、
どうやってパスワードが一致しているかを確認するのさ?」

そう思われたのですね。

ご安心ください。確かにハッシュ化したものは元には戻せません。
しかし、ハッシュ関数にはとっても重要なある性質がありましたね?
そう、同じ文字に対して誰がハッシュ化しても必ず同じハッシュ値が作られる、「同一性」です!

例えば先程と同じように、ハッシュ関数のルールは文字の長さだとしましょう。
パスワードが HelloWorld だったとして、これをハッシュ化すると 10 ですね。

ここで、データベースには HelloWorld の文字は保管せず、ハッシュ値の 10 だけを保管します。

この時点で Web サービスからは元のパスワード HelloWorld の文字は消え、ハッシュ値の 10 だけが残ります。

次に、後日ログインされた際に、ユーザーがパスワードを入力します。
入力されたパスワードは HelloWorld なので、これまたハッシュ値をとると 10 になります。

このハッシュ値 10 と、以前データベースに登録されたハッシュ値 10 を比べると、見事一致していますね!
ということで、これは以前入力されたパスワードと同じハッシュ値なので、パスワードは正しいだろうと判断して、
ログイン成功!ということになるのですね。

もちろん、ここで GoodBye などを入力すれば、このハッシュ値は 7 なので
7 と 10 ではハッシュ値が違い、パスワードは誤っていると判断してログイン失敗、となります。

いやいやいや…!それだと正しくないパスワードでもログインできちゃうじゃん!

「それで OK ってしちゃうと、さっき言ってたみたいに ABCDEFGHIJ とかでもハッシュ値 10 になるじゃん!
パスワードあってないのにログインできちゃうよ!ダメじゃん!」

と思われましたか?
確かに、このままではダメですね。
何がいけないのでしょうか?

…そう、ハッシュ関数、つまりハッシュを作るときのルールが簡単すぎるのですね!

では実際にパスワードを保管する際に使われるハッシュ関数の一つ、 sha512 を見てみましょう。
こちらの関数はとても複雑な計算をしているので(実際の所私もどんな計算をしているのかは知らないのです)
その結果だけ見てみましょう。

HelloWorld を sha512 でハッシュ化すると…

8ae6ae71a75d3fb2e0225deeb004faf95d816a0a58093eb4cb5a3aa0f197050d7a4dc0a2d5c6fbae5fb5b0d536a0a9e6b686369fa57a027687c3630321547596

長い!
0 ~ 9 の数字と a ~ f までの文字を使用して、128 文字あります。
ちなみに、パスワードに用いられるハッシュ関数の特徴としては、

  • どんな長さの文字を入力しても必ずハッシュ値は一定の長さになる
  • 少し文字が違うだけで全く異なるハッシュ値が作られる

というものがあります。
試しに HelloWorld! と、最後に ! を付けただけの文字を sha512 でハッシュ化すると…

c5179301e5619c392fb9b8872b90156ea45e452ea7336d9ee727d5d4a2a95df6a973ddfdeb92bbc14e01aa923591d44835ac32ccd1a71f4681f6a731fae5c238

先程とは全く異なるハッシュ値が作られましたね。
ちなみに、ハッシュ値の長さは先ほどと同じ、 128 文字です。

さて、ここで先ほどの疑問にお答えしましょう。
適当に文字を入力して、ハッシュ値が偶然にも保管されているパスワードと同じ値となってログインできてしまう確率を考えます。
例えば、ハッシュ値の長さが1文字なら 0~9 と a~f の 16 文字なので、 16 分の 1 の確率で同じ値になりますね。
2 文字なら、 00 ~ 0f で 16, 10~1f で 16 …と、 16 パターンの塊を 16 個つくれるので、
16 × 16 = 256 パターンになりますね。
ということで、 256 分の1の確率で同じ値になります。
これを繰り返していくと、文字数の数だけ 16 を掛け算したらいいことが分かるので、
16 × 16 × … × 16 と、 128 回掛けたらいいですね。

つまり、 16 の 128 乗となって、答えは(かなりざっくりですが)

1e+154

…?どういうこと?
これは 1 の後ろに 0を 154 個つけた数、ということになります!
…とりあえず、偶然同じになるのはほぼ無理だという事がわかりますね。

ちなみに隕石が直撃する確率は 100 億分の 1 だそうです。
100 億は 1 の後ろに 0 を 10 個付けた数なので、
偶然にもパスワードのハッシュが同じになる可能性を恐れるくらいなら
隕石が直撃するのに備える方がまだ有益だということですね!

おわりに

お疲れ様でした。
ハッシュ化・ハッシュ値とは何ぞやということ、そしてパスワードとの関係、ご理解いただけましたでしょうか。

ちなみに、ハッシュ化されたパスワードは必ず安全かというと、そういうわけでもありません。
そのままのパスワードを保存するよりは、いくらか安全、という程度です。
そのあたりの仕組みと、対策についてはまた別件として、お話をさせていただきますね。

ハッシュという言葉を聞いたら、「ああ、アレね」みたいな感じで、思い出していただけると嬉しいです。

Let’s share this article!

{ 関連記事 }

{ この記事を書いた人 }

アバター画像
takato_ezaki
記事一覧