セキュリティ · 2026年9月9日

開発者のためのパスワードセキュリティ — 何を保存し、何をハッシュし、何を絶対にやってはいけないか

データベース内の平文パスワードは発生を待っているだけの侵害です。現代のパスワード保存がどうなっているか、「SHA-256でハッシュするだけ」ではなぜ不十分か、代わりに何をすべきかを解説します。

すべてのデータ侵害の開示は同じ弧を描きます:「私たちはセキュリティを真剣に受け止めています。」その後、詳細を読み、パスワードが平文で保存されていたり、MD5でハッシュされていたり、同じデータベースにあったキーで暗号化されていたりすることが判明します。パスワード保存の問題は解決されています — アルゴリズムが存在し、ライブラリが存在し、ドキュメントが存在する — それなのに開発者はまだ間違えています。

この記事では、何を保存すべきか、何を保存すべきでないか、ハッシュ化と暗号化の違い、そしてSHA-256(password)がパスワードハッシュではない理由を扱います。

ルール:絶対に平文を保存しない

データベースが侵害され、平文パスワードがある場合、他のサイトでパスワードを再利用しているすべてのユーザーが侵害されます。あなたのサイトだけでなく — 彼らのメール、銀行、ソーシャルメディア。平文パスワード保存はセキュリティの問題ではありません。道徳的な問題です。

ハッシュを保存してください。常に。

ハッシュ化 vs 暗号化

ハッシュ化は一方通行の変換です。元に戻すことはできません。hashpasswordが与えられた場合、passwordを復元することはできません。確認のみ可能です:入力をハッシュして比較します。

暗号化は双方向の変換です。encrypt(password, key)が与えられた場合、キーを使ってpasswordを復元できます。キーが侵害された場合、すべてのパスワードが侵害されます。

パスワードをハッシュしてください。絶対に暗号化しないでください。平文を復元する必要がある場合(必要ありません)、間違った問題を解決しています。

SHA-256が不十分な理由

一般的な間違い:hash = SHA-256(password)。速く、広く知られており、パスワードには間違っています。

問題は速度です。モダンGPU上のSHA-256は毎秒数十億のハッシュを処理します。SHA-256パスワードハッシュのデータベースを持つ攻撃者は、すべての一般的なパスワード、すべての辞書の単語、すべての順列を数分で試すことができます。

パスワードハッシュ化アルゴリズムは意図的に遅いです。 ブルートフォース攻撃を非実用的にするために、キーストレッチング — ハッシュ関数の数千回の反復 — を使用します:

  • bcrypt — 1999年以来の基準。調整可能なコスト因子。パスワード + ソルト → ハッシュ。すべての主要言語にライブラリがあります。
  • scrypt — メモリーハード。大量のRAMを必要とし、GPU攻撃を困難にします。
  • Argon2 — パスワードハッシュコンペティション(2015)の勝者。メモリーハードで、時間とメモリコストを設定可能。現在のベストプラクティス。
  • PBKDF2 — NIST推NIST推奨、広く利用可能、HMAC反復を使用。Argon2ほどメモリーハードではありませんが、十分にテストされています。

bcrypt、scrypt、またはArgon2を使用してください。 独自のスキームを発明しないでください。SHA-256で一度ハッシュして完了としないでください。

ソルト:なぜすべてのパスワードにユニークなものが必要か

ソルトはハッシュ化前にパスワードに追加されるランダムなデータです。ソルトがないと、同じパスワードを持つ2人のユーザーは同じハッシュを生成します。攻撃者は一般的なパスワードのハッシュを事前計算し(レインボーテーブル)、データベースと照合できます。

ユーザーごとにユニークなソルトがあると、パスワードが同じでもハッシュが異なります。レインボーテーブルは機能しません。攻撃者は各パスワードを個別にブルートフォースする必要があります。

モダンなパスワードハッシュ関数(bcrypt、Argon2)は自動的にランダムなソルトを生成します。ソルトを個別に管理する必要はありません。パスワードをハッシュ関数に渡すと、残りを処理します。

何を保存すべきか

各ユーザーについて、以下を保存します:

  • パスワードハッシュ(bcrypt/Argon2の出力、ソルトとコストパラメータを含む)
  • ハッシュアルゴリズム(bcrypt、argon2など)
  • コストパラメータ(bcryptラウンド、Argon2メモリ/時間)

保存しないもの:

  • 平文パスワード
  • ソルトを別途(ハッシュ関数の出力に含まれています)
  • パスワードを復号化できる可能性のある「暗号化キー」
  • パスワードのヒント(情報を漏洩します)

bcryptのハッシュ出力は次のようになります:$2b$12$LJ3m4ys3GzF4VQ.YOUR.HASH.HERE。$2b$はアルゴリズムを識別し、12はコスト因子で、残りはソルト + ハッシュです。ログイン試行を確認するには、同じパラメータで送信されたパスワードをハッシュし、比較します。

コスト因子

bcryptのコスト因子はハッシュの速度を決定します。各増加は計算時間を2倍にします:

  • コスト10:ハッシュあたり約10ms(ユーザーには速く、攻撃者にも速い)
  • コスト12:ハッシュあたり約40ms(合理的)
  • コスト14:ハッシュあたり約160ms(攻撃者には遅く、ユーザーには気づく)
  • コスト16:ハッシュあたり約640ms(ほとんどのログインフローには遅すぎる)

2026年のベストスポット:bcryptコスト12-14、64MB以上のメモリと3以上の反復を持つArgon2。 目標は各ハッシュ試行を遅くし、数十億のパスワードのブルートフォースに数年かかりますが、ユーザーがログイン時に遅延を感じない程度に速くすることです。

レート制限

ハッシュ化だけでは不十分です。攻撃がログインエンドポイントに対して毎秒数百万のパスワードを試せる場合、bcryptでさえ救えません。

ログイン試行を制限 同じIPまたはアカウントからの5-10回の失敗後、アカウントを一時的にロックするかCAPTCHAを要求します。これによりブルートフォース攻撃は最小限に抑えられます。

ユーザー名またはパスワードが間違っているかどうかを明かさない 「無効なユーザー名またはパスワード」は「そのメールのアカウントが見つかりません」より安全です。後者は攻撃者に有効なユーザー名を伝えます。

持続的な失敗後のアカウントロックを追加 10-20回の失敗後、アカウントを15分間ロックするか、ロック解除にメール確認を要求します。

パスワード生成

パスワードを生成する場合(ユーザー、APIキー、トークン用):

  • 最低12文字 モダンなハードウェアに対して8文字では不十分です。
  • 大文字、小文字、数字、記号を含める しかし長さは複雑さよりも重要です。
  • CSPRNGを使用(暗号学的に安全な擬似乱数生成器)。Math.random()は安全ではありません。
  • 予測可能なパターンを絶対に生成しない Password1!は複雑に見えますが、簡単に推測できます。

最良のパスワードはCSPRNGから生成されたランダムな文字列です。パスワードマネージャーを使用して保存してください。ユーザーに複雑なパスワードを覚えさせないでください — 生成されたパスワードを渡し、マネージャーに管理させてください。

よくあるエラー

  • SHA-256またはMD5で一度ハッシュ — 速すぎ、ソルトなし、容易にブルートフォース可能。
  • 静的ソルトの使用 — すべてのユーザーが同じソルトを共有する場合、レインボーテーブルが機能します。
  • ソルトを別途保存 — ソルトが別のテーブルにある場合、データベースを侵害した攻撃者は両方を取得します。
  • ハッシュ化の代わりに暗号化 — パスワードを復号化できる場合、キーを持つ攻撃者もできます。
  • レート制限なし — bcryptでさえ無制限のログイン試行に脆弱です。
  • ユーザー名の存在を明かす — 攻撃者に有効なアカウントの列挙を助けます。
  • パスワード生成にMath.random()を使用 — 予測可能で、暗号学的に安全ではありません。

クイックリファレンス

やる やらない
bcrypt、Argon2、またはscryptを使用 SHA-256またはMD5を使用
ライブラリにソルト処理を任せる ソルトを自分で管理
ログイン試行を制限 無制限のパスワード試行を許可
CSPRNGでパスワードを生成 Math.random()を使用
ハッシュのみを保存 平文または暗号化されたパスワードを保存
「無効な資格情報」と言う 「間違ったパスワード」と言う

試してみる

安全なランダムパスワードを生成したり、テスト用に文字列をハッシュする必要がある場合は、ブラウザベースのツールを使用して操作がローカルで行われるようにしてください。パスワードは単純な生成タスクでサーバーに触れるべきではありません。