パスワード保存方法の過去と現在そして未来

2015-09-13

はじめに

なんで パスワード の保存方法に Bcrypt を使っているの?

そんな疑問をWebアプリケーションのパスワード管理の歴史と共に考察。

軽く調べた程度なので、間違っている箇所があるかもしれません。

導入

インターネットやパーソナルコンピュータが発達し、アプリケーションサービスプロバイダ(ASP)によって

多くの人々に様々なサービスが提供されるようになりました。

サービスを利用するためには、そのサービスを利用可能なユーザであるかどうかの判断をするために、

ID, パスワードを用いた個人認証が多くのサービスで導入されています。

パスワードはどうやって データベースに保存されている(た)のでしょうか?

大昔編その1 - Plainテキストでの保存

入力された値をそのままの形でデータベースに保存する方法です。

経営リスクも非常に高いので、今ではかなりの希少種です。

次のように保存されているのではないでしょうか?

email password
kengo@kengos.jp 123456

問題点

セキュリティ上非常に脆弱である。(見ただけでパスワードが分かる)

データベースが覗かれた場合、すぐにその人になりすましてログインすることができる。

覗くのは システム(データベース)の管理者である場合もあるし、外部からの攻撃による場合もある。

大昔編その2 - 単純なHash化

Plainテキストを Hash関数(この時代の多くはMD5など)を利用して Hash値をデータベースに保存する方法

email password
kengo@kengos.jp e10adc3949ba59abbe56e057f20f883e

※Ruby の Digest::MD5.hexdigest('123456')で変換した値

アプリケーションの開発者からは 暗号化してありますので安全です!と言われたりします。

そもそも暗号化。。。

問題点

単純なHash化であれば、オフライン総当たり攻撃などの手法を用いれば比較的簡単に解析が可能である。

また次のような攻撃も行える。

1. (DBを覗くことができる)ユーザが よく利用されるパスワード(`123456`) などを用いて会員登録などを行う。

2. 自分のユーザの `password` の値に入っている文字列を確認する(`e10adc3949ba59abbe56e057f20f883e`)

3. その値と同一のユーザ(kengo@kengos.jp)のパスワードが `123456` であることが確認できる

現代編 その1 - saltの導入とmd5 から sha2 へ

多くのサイトが導入していると思われる方法です。(過去数年のサイト?)

salt という方法を用いて 同一のパスワードが入力された場合でも違う文字列にするという方法です。

email password salt
kengo@kengos.jp 72a54ea704ab4fbf7175f3b4b5341abe aaaa
cracker@example.com b692024be1f04466961f569f6fa244cf bbbb

※saltを用いてMD5でHash化(Digest::MD5.hexdigest("123456" + salt))したもの

元のパスワード + salt という形式で パスワードをHash化することで、元の文字列が同じでもユーザごとに異なる値を 生成することができます。

また現在では md5よりsha2(sha-256)などを利用することが多いです。

(よくわかっていませんが、計算量がmd5と比べて多くなるのでということでしょうか?)

これは 事前にHash値を計算しておく レインボーテーブルを用いた攻撃に有効です。

ただ、現時点では安全な方法とは言いがたい方法です。(2-3年もすれば大昔カテゴリに異動でしょう。)

ただ、salt値も漏洩するため、オフライン総当り攻撃などへの対策は完全であるとはいえません。

pepper

データベースの漏洩 = saltの漏洩という図式であるので、 salt導入だけではなく、pepperの導入もするパターンも見受けられます。

システム全体で同一の pepper を導入します。

以下のように pepper も混ぜて Hash化します。

Digest::MD5.hexdigest("123456" + salt + pepper)

このようにすることで データベースの値のみ漏洩した場合については 元の値を復元することができなくなります。

ただ、データベースのデータ漏えい が起きたのであれば, アプリケーションプログラムの漏洩(pepperの漏洩)が発生している可能性も高いです。

ないよりはあったほうがいいけど、まあ 胡椒レベル の使われ方という感じでしょうか。

現代編 その2 - ストレッチングの導入

オフライン総当り攻撃の時間を稼ぐためにストレッチングを導入することがあります。

ストレッチングとは, ハッシュ関数を n 回繰り返して保存するパスワードを生成する方法です。

単純な Hash化にかかる時間を 0.0001秒だとします。
ストレッチングを 1000回行うと 0.1 秒かかることになります。

オフライン総当り攻撃により

10億パターン試すと そのユーザのパスワードがわかるとします。

ストレッチングをしていない場合
  10,000s(約2.7時間) でパスワードの解析が可能となります。

ストレッチングをする場合
  1億秒(約3.2年) でパスワードの解析が可能となります。

ストレッチングをすることにより解析にかかる時間が伸びていくことがわかるかと思います。 (時間については適当)

デメリット

ユーザログインにかかる時間の増加

計算量が多くなることで、ユーザのパスワード認証に 0.1 秒かかるようになってしまいます。

毎日多数のユーザがログインするようなサイトの場合は、致命的な場合があるので、ストレッチング自体を

導入しない or 減らす といったパターンも見受けられます。

課題

現代においては 1秒間に数億回のHash計算(1回あたり1ナノ秒程度)を行うことができるようになっています。

現状では 1000回程度のストレッチングをすることである程度の時間(ユーザのパスワードリセットなど)を稼ぐことができると言われています。

もし、1秒間あたりの計算回数が増えた場合、どうすればよいでしょうか?

当然それに合わせて ストレッチングの回数を増やしていく必要があります。

この対応のためには ストレッチング回数をデータベースに保存するようにしておくとよいでしょう。

以下のような形でしょうか?

email password salt stretching
kengo@kengos.jp 72a54ea704ab4fbf7175f3b4b5341abe xxxx 1000

ストレッチング回数が1000回で安全でなくなりそうに場合、

ユーザ認証成功時に 新たな ストレッチング回数で 計算しなおしたパスワード を再設定するなどの方法でマイグレーションをしていくことができるようになります。

現代編 その3 - bcrypt の登場

ここまででパスワード管理を行っていくDBには

実際にパスワードを保存する項目, Salt値を保存する項目, ストレッチング回数を保存する項目

の3つが必要になっています。

アプリケーションを作る上では複雑さをなるべく減らしたいので、こういう項目もなるべく減らしたいですよね。

bcrypt を利用することで この項目を1つにすることができます。

以下のような書式で保存されています。

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

この文字列中に ストレッチング回数, salt, Hash化後の値の3つが含まれています。

現代編 - 課題

いくらアプリケーション側で対策をしようにも、ユーザサイドが単純なパスワード(password123456など)

を利用していたのであれば、簡単になりすましされてしまいます。

もちろん, 複雑なパスワードでないとパスワードに設定できないというサイトもあります。

しかし、そのようにすると、会員登録などのアクションのコンバージョンが下がったりなど別の問題が発生します。

この問題は 会員登録のコンバージョンを上げるというミッションを持つグループとセキュリティのリスクをハンドリングするグループとの間で

しばしば対立します。

また、ユーザは覚えきれずに ID/パスワード を 紙に書いたり、自分のPCに保存したりしてしまいます。

覚えきれないから、単純なパスワードをどのサイトでも設定してしまい、

パスワード漏洩時に他のサイトになりすましログインされてしまいます。

(そういった対策のために、主要サービスでは2要素認証が入っていたりします。)

どのサイトも 他のサイトと同一のパスワードを設定しない でくださいといっていますが、

そもそもユーザ認証を ID/パスワード に頼らざるを得ないのが問題です。

良識あるサイトの場合は OAuth認証による TwitterログインやFacebookログインなどを実装し、

唯一複雑なパスワードを覚えていないといけないのを Twitter, Facebookなどのサービスにできるようにしています。

(パスワード漏洩時のリスクを低減したり、会員登録の敷居を下げる別の意味合いもあります)

未来編

パスワードを利用しない方法が ID/パスワード認証方式の代わりになるものになるでしょう。

どのユーザも保持しているデバイスを用いた認証(スマートフォンなど)が有力と言われています。

実際にそのような機能をもった製品も発売されています。

英国CertiVox 社の M-Pin が NTTソフトウェア と提携し、日本に進出したり。
 (https://www.certivox.com/blog/ntt-partnership-with-certivox)

 それが AWSで販売されていたり https://aws.amazon.com/marketplace/pp/B00PB4WX64