[暗号技術入門] 安全なパスワードの保存方法

目次の表示
  1. 平文パスワード(アンチパターン)
  2. シンプルなパスワードハッシュ(安全ではない)
  3. ソルト付きハッシュ化されたパスワード(安全性が不十分)
  4. 安全なKDFベースのパスワードハッシング(推奨)
  5. パスワードベース認証に対する攻撃

ソフトウェア開発では、パスワードベースのユーザー認証が頻繁に発生し、ユーザーがサインアップ、認証、パスワードの変更を行えるようにする必要があります。 それと同時に攻撃者がユーザーアカウントを保持するデータベースにアクセスできたとしても、保存されたパスワードを平文の値に復号できないようにユーザーパスワードを安全に保存する仕組みを作る必要があります。

WebサイトやWebアプリを開発する場合、通常はログイン後にアクセス可能な管理パネルがあり、ユーザー名 + パスワードに基づいています。モバイルアプリ、Webサービス、その他のパスワード保護されたシステムでも同様です。すべてのシステムで安全なパスワードの保存(安全なパスワード管理 / 強力に暗号化されたパスワードの保存)が必要です。

開発者は、サイト、アプリ、その他のシステムのユーザーパスワードを、他のユーザーデータと同様にデータベースに保存することがよくありますが、ほとんどのシステムはハッシュ化、暗号化、またはパスワード認証スキームを使用しています。 パスワードベースの認証のためのパスワードの保存を実装する方法はいくつかあります。 最も一般的なものを以下の表に示します:

アプローチ セキュリティ コメント
平文のパスワード 極めて低い 絶対にしないでください。サーバが侵害されるとすべてのパスワードが漏洩します
簡単なパスワードハッシュ 低い 辞書攻撃に対して脆弱
ソルト付きハッシュ化されたパスワード 平均 GPUベースおよびASICベースのパスワードクラッキングに脆弱
安全なKDF関数(Argon2など) 高い 推奨される強力なKDFパラメータを設定して使用すること

これらのパスワード保存方法について、そのセキュリティレベル、強み(メリット)と弱み(デメリット)について見ていきたいと思います。

平文パスワード(アンチパターン)

パスワードの保存とパスワードベースの認証において、最も簡単でかつ非常に安全でない方法は、データベースに直接書かれた平文のパスワードを使用することです。 これはソフトウェア開発におけるアンチパターンです。

  • 平文パスワードをデータベースに保存するのは絶対にやめてください
    • 管理者はユーザーのパスワードを見ることができてしまいます。
    • 多くのユーザーは複数のサイト/アプリで同じパスワードを使い回しているため非常に危険です。
    • もし誰かがサーバーをハッキングしてデータベースにアクセスできた場合、平文ですべてのユーザーのパスワードを見ることができてしまいます。

管理者はユーザーのパスワードを知ってはいけませんが、緊急の場合には変更できる必要があります。 ですが、それを実現するために平文パスワードである必要はありません。 以降で説明する鍵導出関数 (KDF) を使っても、緊急時のパスワードの変更はできます。

シンプルなパスワードハッシュ(安全ではない)

パスワードの保存とパスワードベースの認証のための比較的簡単で安全ではない方法は、SHA-256(password) のようなシンプルなパスワードハッシュを使用し、それを直接データベースに書き込むことです。

  • サーバは受け取ったパスワードが正しいかを確認するために、単に ハッシュ(確認用のパスワード) をデータベースから取得したパスワードハッシュと比較します。
  • パスワードをハッシュ化してデータベースに保存するのは非推奨です
    • なぜなら、ハッシュは辞書攻撃に対して脆弱であるからです。
    • データベースにアクセス権を取得したクラッカーは、最も一般的に使用される1000万〜2000万のパスワードのハッシュを保持する辞書を使用し、ほとんどのパスワードを解読できます。
    • 辞書攻撃プロセスは非常に高速です。なぜなら、辞書から取得したハッシュをパスワードハッシュと比較するだけだからです。
    • 検索すれば辞書攻撃に使用できる無料の辞書(ワードリスト)をダウンロードすることができます。

ソルト付きハッシュ化されたパスワード(安全性が不十分)

パスワードの保存とパスワードベースの認証のためのより複雑で比較的安全な方法は、ソルト付きハッシュ化されたパスワードを使用することです。 これはデータベースに ソルト + ハッシュ(パスワード + ソルト) のペアとして書き込まれます。 ハッシュ関数にはSHA-256などの強力な暗号ハッシュが使用できます。

  • データベースにユーザごとに異なるランダムなソルトを保持し、異なるパスワードハッシュと一緒に保持し、パスワードがデータベースに書き込まれるたびに更新することです。そのため、同じパスワードは毎回異なる暗号文 ソルト + ハッシュ として暗号化されます。
  • サーバは受け取ったパスワードが正しいかを確認するために、データベースからソルトを使用して ハッシュ(確認用のパスワード) を計算し、計算されたハッシュをデータベースからのハッシュと比較します。
  • この方法は辞書攻撃を防ぐのには適していますが、GPUやASICに基づく総当たりパスワードクラック攻撃を防ぐことはできません。
  • これは、HMAC(key, msg)の代わりにhash(key + msg)を使用する場合と同じセキュリティ上の問題があります。例えば、伸長攻撃があります。
  • 基本的に、ソルト付きハッシュ化されたパスワードを保持することは以前の方法よりも安全です。しかし、単純なハッシュではなく、例えばArgon2やScryptなどの総当たり攻撃に耐えるパスワードハッシュ関数を使用することが推奨されています。

安全なKDFベースのパスワードハッシング(推奨)

安全なパスワードの保存とパスワードベースの認証のために最も複雑で最も安全な方法は、安全なKDFベースのパスワードハッシュを使用することです。これはデータベースに salt + KDF(password, salt) のペアとして書き込まれます。 鍵導出関数(KDF)は強力で安全である必要があり、例えばScryptArgon2などの適切に選択されたパラメータを使用します。

  • 異なるランダムなsaltを各暗号化されたパスワードに保持するアイデアは、ScryptやArgon2などの安全なKDF関数によって導出された鍵と一緒に保持します(適切なイテレーション数とRAM消費を設定していることが前提です)。
  • サーバが受け取ったパスワードが正しいかを確認するためには、データベースからsaltを取得し、同じKDF関数とKDFパラメータを使用して、データベースにパスワードが保存されたときと同じようにパスワードから鍵を導出します。そして導出された鍵をデータベースの鍵と比較します。
  • この方法はほとんどの攻撃に対して耐性があり、ソフトウェア業界では標準と見なされています。
    • 選択されたKDFパラメータを持つKDF関数と同じくらい安全です。
    • クラッカーは総当たり攻撃を実行できません。なぜなら、パスワードの推測が遅すぎるため、現代のコンピュータやCPU、GPU、専用のASICハードウェアを使用しても遅くなります。

結論 : データベースに暗号化されたパスワードを保持するためにArgon2Scryptなどの安全なKDF関数を使用してください。決して平文のパスワードを使用しないでください。

パスワードベース認証に対する攻撃

セキュアなパスワードストレージを使用することは、Webアプリ、モバイルアプリ、およびインターネットサービスのセキュアなパスワードベースの認証プロセスの一部に過ぎません。 パスワードベースの認証を使用するシステムは、多くの攻撃の対象となります:

  • パスワード推測攻撃:攻撃者が多数のログインを並行して試みることで、ユーザーのパスワードを推測・総当たりする攻撃
    • 各誤ったログイン試行後にログイン遅延を増加(再度ログイン可能になるまでの待機時間)することで簡単に解決できます。遅延やロックアウトはIPアドレス + ユーザー名で行うべきで、正規のユーザーにログイン問題が発生しないようにします。
    • セキュアなKDFベースのパスワードストレージはパスワード推測プロセスを遅らせるため、強く推奨されます。
    • 2〜3回の失敗したログイン試行後にCAPTCHAを使用すると、より安全な保護が提供されます。
  • DoS攻撃:攻撃者がシステムを過負荷にするために多数回ログインを試みるか、同じユーザーに対して無効なログイン試行が多すぎてユーザーアカウントをロックしようとする攻撃
    • この攻撃からの保護は、CAPTCHAを使用し、各ログイン試行後に特定のIPアドレスに対してログインを遅延させます。
  • 傍受と再送攻撃:攻撃者が認証通信を傍受し(ログイン・パスワード・認証チケット・その他の資格情報をスニッフィング)、後で傍受した資格情報を使用してログインしようとする攻撃
    • ほとんどのシステムは、TLS(暗号化された接続)を使用して認証資格情報(パスワード・認証チケット)をサーバーに安全に送信することで、この問題を解決します。
    • 他の解決策には、チャレンジレスポンスベースの暗号認証スキームがあり、これは Kerberos プロトコルで使用されているスキームなどがあります。
  • 中間者攻撃:攻撃者がサーバーとクライアント間の傍受トラフィックを変更して、ユーザーを騙してログイン資格情報を明らかにしようとする攻撃。
    • これは、サーバー証明書でサーバーを認証するTLSセキュア接続を使用することで解決されます。
    • 一部のシナリオ(例:オンラインバンキング)では、クライアントもデジタル証明書やOTP(ワンタイムパスワード)によって認証されます。
  • サーバーの侵害攻撃:認証サーバーとそのデータベースが侵害され (ハッキングされ)、すべての認証データが漏洩した場合、攻撃者はユーザーの平文パスワードを明らかにできないはずです。
    • まず、認証サーバーが侵害された場合、攻撃者は常に不正アクセスを取得することになります。なぜなら、彼らはユーザーの正当なセッション(ログインおよび成功したログイン後の通信)を傍受して使用し、ユーザーをなりすますことができるからです。
    • 強力なセキュアなパスワードストレージメカニズムを使用することで、ユーザーのパスワードが平文で明らかにされるリスクが軽減されます。それでも、認証サーバーにアクセス権を取得した攻撃者は、ログイン時に各ユーザーの平文資格情報(ユーザー名 + パスワード)を傍受し、盗む可能性があります。
    • バックドア付きサーバー攻撃は次のように停止できます:クライアントはランダムな数値 r を生成し、認証として HMAC(パスワード, r) を送信します。サーバーはHMACを保存されたパスワードと比較します。このプロセスは、クライアント側の Scrypt または Argon2 の計算とサーバー側で安全に保存されたパスワード(ScryptまたはArgon2ハッシュ化)と組み合わせることができます。この場合、クライアントソフトウェアが侵害されていない限り、認証サーバーにアクセス権を取得した攻撃者はユーザーのパスワードを平文で取得できません。
    • Webアプリケーションでは、サーバーが侵害された場合、クライアント自体を危険にさらすためにJavaScriptコードを注入する可能性があります。デスクトップアプリやモバイルアプリでは、クライアントはサーバーが侵害された場合でも比較的安全です。

Webサイト、アプリ、サービスにセキュアなパスワードベースの認証を実装する方法に関する結論は以下の通りです:

  • 強力な設定を持つArgon2ハッシュなどのセキュアなパスワードストレージを使用します。
  • 認証サーバーをできるだけ安全に保ちます。侵害された場合、システム全体が危険にさらされます。
  • 認証サーバーとクライアント間はTLSまたは他のセキュアな通信チャネルを使用します。