【システム開発】パスワードの安全な保存方法

 パスワードといえば、最も流出させてはいけないセンシティブな情報のひとつです。パスワードが流出すれば、そのユーザーに偽装してWebサービスを利用したり、個人情報を盗み見るなどが容易にできてしまいます。

 今回は、パスワードの安全な保存方法について考えてみましょう。

はじめに

 Twitter社がパスワードを平文でログに吐いていたという話は記憶に新しく、内部での漏洩とはいえ重大な事件として話題になりました。

 複数のサイトで共通のパスワードを使わない、というのはセキュリティ意識の高いユーザーなら常識ですが、数多くあるウェブサイトのID、パスワードを全て適切に管理することは非常に難しく、共通のパスワードを利用しているユーザーもいるはずです。そうなると、平文のパスワードとユーザーIDとして扱われやすいメールアドレスなどが見える状態にあるのは非常に好ましくありません。

 たとえ内部での漏洩であったとしても、内部の人員が絶対的に信頼できるような状況でなければ大きな問題となります。そして、そのようなケースは残念ながら存在しないのが現代社会です。

パスワードの漏洩を防ぐには

 情報の漏洩は、完全に防げるものではないと理解することが大事です。それがどんなに堅牢なシステムであったとしても、アクセスできる全ての情報に漏洩の危険があると認識してください。

 漏洩しないシステムとは、即ち、外部から一切アクセスできないシステムということになりますが、それは全く役に立たないただの箱であることと同義です。

 Webサービスやその他のアプリケーションでは、情報が漏洩したときに最もダメージが少ない手段を採択して運用していくことが唯一の解となるのです。

ハッシュ化する

 パスワードなどのセンシティブな情報を暗号化するのはよい手段です。特に不可逆暗号であるハッシュ化の技術は、パスワードの保管に広く用いられています。

 現在は、SHA2アルゴリズムを用いたハッシュ関数が有力です。この対策が有効な理由は、流出したとしてもパスワードを復元することが難しい点にあります。

 例えば、「password」という文字列をSHA2の256bitアルゴリズムでハッシュ化してみましょう。

5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

 実際には、永続化インターフェースであるデータベースなどには、このハッシュ化された値が書き込まれることになります。このとき、ハッシュ値は不可逆であるためデータベースの中身が漏洩したとしても、それ単体では攻撃者に有益な情報を与えることはありません。

 パスワードのハッシュが漏洩したところで、元々のパスワードを復元することができないためです。

saltを加える

 しかし、sha2 decryptなどで検索するとわかるとおり、世の中にはハッシュ値と元のパスワードの値をデータベース化して突破を試みようとするサイトがあります。

 これらのサービスは、文字列を手当たり次第にハッシュ化したものをデータベース化しており、ただの文字列(特にパスワード利用率の上位のもの)であればハッシュ値からいとも簡単に復元されてしまうことでしょう。

 つまり、パスワードをただsha2関数を用いてハッシュ化しただけでは、データが漏洩した際に元のパスワードを復元される可能性が非常に高いということがわかります。

 これを防ぐために考案されたものがsaltと呼ばれるランダムな文字列であり、saltを付与することによって同じ文字列でも異なるハッシュ値を生み出すことが可能となるのです。

 saltを用いて先ほどの「password」という文字列をハッシュ化してみましょう。今回はsaltとして「33ef」という文字列を文字列の末尾に付与した、「password33ef」という文字列を利用します。

af10f06bb561ebb5dbe24f025a5d41037d9809f25f3cd57c879e6764ee3a02e2

 当然ですが、先ほどの結果とは異なるハッシュ値が生成されました。

 saltを利用する利点は、ランダムな文字列を付与することで同一の文字列に対するパターン数が爆発的に増えるため、事前にハッシュを計算してデータベースを作成しておくなどの攻撃手法が限りなく困難となることです。

 saltは、通常パスワードのハッシュ値と共に保管されますが、saltとパスワードのハッシュ値が同時に漏洩したとしても、上述した理由により攻撃者には為すすべもありません。ハッシュ値は不可逆であるため、元の文字列を推測することが非常に困難だからです。

ハッシュ関数を繰り返す

 もっと強度を上げることもできます。ハッシュ値は文字列ですから、それに対してハッシュ関数を実行することで、新たなハッシュ値を生成することができます。さらに、ハッシュ値を生成する毎に異なるsaltを加えたり、文字列を数回結合するのもよいでしょう。

 こうして複雑度を上げて独自のハッシュ関数を作り上げていくことで、より堅牢な暗号化が可能となります。

実際に利用してみる

 MySQLでSHA2関数が利用できますので実際にやってみましょう。

 実行環境をお持ちでない方は、paiza.ioなどで確認できます。

SELECT SHA2('password', 256);    # password をハッシュ化
SELECT SHA2('password33ef', 256);    # password + saltをハッシュ化
SELECT SHA2(SHA2('password', 256), 256);    # passwordを2回ハッシュ化

 それぞれ異なる結果を得られたことが確認できたでしょうか。

 ユーザー認証を行うときは、ユーザーから入力されたパスワードに対して、全く同じアルゴリズムを適用し、それをデータベースのハッシュ値と比較すればよいということになります。

今回は例としてMySQLを利用しましたが、パスワードなどを含むSQLクエリがquery logやslow logなどのログに残らないように細心の注意を払ってください。場合によってはアプリケーション側で実装したほうが安全な場合もあります。

まとめ

 パスワードの安全な保管方法に絶対の正解はありませんが、このように漏洩したとしても破られにくい技術を用いることで安全性を高めることができます。

 今回の例でも挙げたとおり、複雑性を上げることで実質復元できないようにするなどの方法は有力です。しかし、SHA1の衝突攻撃に代表されるとおり、いつそれらの技術が破られるかわかりません。

 常にセキュリティの情報に耳を傾け、アプリケーションをバージョンアップし続けることも忘れてはならないことのひとつです。