In this article
パスワードを安全に保存するための9つのベストプラクティス
パスワードを安全に保存することは、小規模なスタートアップから大企業まで、あらゆる組織にとって課題です。
創業間もないスタートアップでは、リソース不足から、パスワードを適切に保存するための深い専門知識を持たない経験の浅い開発者を採用せざるを得ない場合があります。認証は開発プロセスの比較的早い段階で追加されるため、パスワードの保存方法が不適切になる可能性があります。
その結果、アプリケーションの基盤となる部分の実装が不十分なままになります。もちろん、アプリケーションの中核を担うモジュールほど、後から変更すると不具合が発生する恐れがあるため、プロジェクトの進行中に開発者が変更をためらうようになります。
こうして不適切な認証の実装が引き継がれ、ついには事態が悪化し、誰かにユーザーのパスワードを盗まれてしまいます。
アプリケーションセキュリティのベストプラクティスを開発段階で実践すれば、そもそもシステム侵害を防ぐうえで重要な役割を果たします。しかし、100%安全なものはないため、ユーザーのパスワードを守るための対策が必要です。
この記事では、パスワードを安全に保存するための重要なベストプラクティスをご紹介します。
1. データベースとコンテナを保護する
データベースセキュリティは、厳密にはパスワードに関するベストプラクティスではありません。データベースに保存されているすべてのデータに関わるものなので、見落としてはいけません。
そもそも攻撃者がデータにアクセスできなければ、データを復号することもできません。データベースベンダーが推奨するセキュリティのベストプラクティスも確認しましょう。
もちろん、これはデータベースだけでなく、すべてのシステムに当てはまります。Dockerのような一般的なコンテナエンジンを使用している場合、Dockerに伴うあらゆる問題の影響を受ける可能性があります。コンテナセキュリティをおろそかにせず、必要に応じてシステムが監視されていることを確認してください。
2. すべてのパスワードをハッシュ化する
パスワードを平文で保存してはいけません。必ずパスワードをハッシュ化し、元のパスワードではなくハッシュを保存してください。パスワードの保存には、ハッシュは暗号化よりも適しています。ハッシュは元に戻せないためです。
ユーザーがログインを試みたときは、入力されたパスワードからハッシュを再生成し、新しいハッシュが登録時に保存したものと一致するか確認できます。データベースにアクセスできる人がいても、そのハッシュから元のパスワードを読み取ったり推測したりすることはできません。あなたや同僚であっても同じです。ハッシュを使えば、盗まれる可能性のある暗号化キーも不要です。
3. 強力なハッシュ関数を使う
ハッシュ関数はすべて同じではありません。暗号学的に安全でないものもあれば、計算が速くなるよう設計されたものもあります。パスワードのハッシュ化には、計算が速い関数は避けましょう。
計算が速いハッシュ関数を使うと、攻撃者は大量のランダムな文字列を総当たりで試し、ハッシュに隠されたパスワードを見つけられてしまいます。攻撃者の作業を難しくする必要があります。登録時やログイン時に自分でパスワードをハッシュ化する際には、こうした遅い関数を使うことになりますが、何百万ものランダムな文字列を処理する必要はありません。
OWASPは、Argon2を使ったパスワードのハッシュ化を推奨しています。利用できない場合はbcryptを、bcryptも利用できない場合はscryptを使いましょう。
4. パスワードにソルトを加える
ソルトとは、パスワードをハッシュ化する前にランダムな文字列を追加することです。これにより、よく知られたパスワードから生成されるハッシュが同じになるのを防げます。攻撃者がパスワードと対応するハッシュをまとめたテーブルを持っていれば、ユーザーが使っているパスワードを照合できてしまうかもしれません。このテーブルにはpasswordのハッシュが載っていても、&()/&IJDNSBAEpassword.のハッシュは載っていない可能性があります。
また、ユーザーは複数のアプリケーションで同じパスワードを使い回す傾向があります。攻撃者が複数の人気アプリケーションから漏えいしたパスワードを入手した場合でも、ハッシュ化の前にソルトを加えていれば、パスワードを照合されるのを防げます。
ソルト文字列は、パスワード文字列と一緒にデータベースに保存されます。Argon2やbcryptなどの最新のハッシュライブラリは、ハッシュ化の前にパスワードへ自動的にソルトを加えます。
5. パスワードにペッパーを加える
ペッパーの追加方法はソルトと同じで、ハッシュ化の前にランダムな文字列を追加します。
両者の違いは、ペッパーの場合、すべてのパスワードに同じ文字列を使う点です。また、ペッパー文字列はデータベース内のパスワードと一緒に保存しません。ファイルシステムやオブジェクトストレージなどに保存します。パスワードデータベースと同じ場所でなければ、保存先はどこでもかまいません。
ハッカーがデータベースへのアクセスに成功しても、必要なデータの一部が欠けているため、パスワードのハッシュと正しいパスワードを照合するのは格段に難しくなります。
6. ワークファクターを更新する
ハッシュ関数の計算には時間がかかりますが、コンピューターの処理速度が上がるにつれて、計算も速くなっています。コードを書いた当時は数秒かかったハッシュの生成も、高性能なコンピューターを使う攻撃者なら数ミリ秒で実行できるかもしれません。
この問題に対処するため、ハッシュ関数には「ワークファクター」と呼ばれるパラメーターがあります。ワークファクターを設定すると、ハッシュ関数の反復回数が増え、処理にかかる時間も長くなります。
ワークファクターを設定する際には、2つの点を考慮する必要があります。一方では攻撃者にとってハッシュ化を簡単にしないこと、もう一方ではログインを難しくしすぎないことが重要です。そのため、一般的にはワークファクターを極端に高く設定するのは避けるべきです。
インフラをアップグレードしてサーバーの性能が向上した場合は、ワークファクターも引き上げ、性能向上をセキュリティの強化にも活かしましょう。
7. ユーザーにパスワードのリセットを強制しない
かつては、数週間ごとにユーザーにパスワードを変更させることがベストプラクティスとされていました。盗まれたパスワードに有効期限を設けるという考え方です。しかし実際には、ユーザーに不満を感じさせ、より簡単で安全性の低いパスワードを選ばせる結果につながりました。
コンプライアンス規制により、こうした時代遅れの慣行に従わなければならない場合、避けることはできません。しかし、外部要因によってそのようなガイドラインに従う必要がないなら、ユーザーにパスワードの変更を求めないでください。長期的に見て、パスワードの質を高めることにつながります。
8. 複雑さよりも長さを重視する
一般に、パスワードは複雑さより長さが重要です。長いほどプログラムによる解読に時間がかかります(場合によっては何年もかかります)。たとえば、IonceateahamburgerinLondonのほうがx5§.11#よりも覚えやすいでしょう。
そのため、数字や特殊文字の使用をユーザーに求める必要はありません。入力内容は自由にし、5文字を超える長さにするよう求めましょう。
9. 辞書や拒否リストと照合する
ユーザーに根拠なく複雑なパスワードを求める必要はありませんが、新しいパスワードを公開辞書や拒否リストに載っている、よく知られたパスワードと照合することをおすすめします。新しいパスワードがこれらの情報源に含まれていた場合は、ユーザーに知らせて使用を避けるよう促しましょう。
ハッカーも、盗んだハッシュと照合するために、こうした情報源にあるパスワードを利用します。これらのリストと照合することで、ハッカーが平文のパスワードを突き止めるのをさらに難しくできます。
パスワードを安全に保存するためのベストプラクティスは、SDLCに欠かせない要素です
パスワードはアプリケーションに欠かせない要素です。パスワードを適切に保存することは、長期的に重要です。ユーザーデータの重要度によっては、侵害されたパスワードを保存していることで、会社全体が破綻する可能性もあります。
不適切なパスワード管理は、さまざまなセキュリティ上の問題につながります。外部からの攻撃だけでなく内部からの攻撃も可能にし、他のアプリケーションから流出したパスワードの使い回しによるリスクも高めます。ユーザーの協力が得られなくなれば、不満を招き、コンプライアンスの低下によってセキュリティリスクが高まる可能性があります。さらに、サービスの利用をやめる人が出てくるかもしれません。
重要なソフトウェアを構築する際は、開発プロセスのすべての層でセキュリティのベストプラクティスを実践する必要があります。パスワードセキュリティは、セキュアなSDLCの一部にすぎません。そもそも攻撃者がパスワードにたどり着けないようにしましょう。Snyk Codeの静的アプリケーションセキュリティスキャナーは、コードに既知の脆弱性がないか確認し、修正方法を提示します。