PBKDF2 を利用することは「パスワードを“絶対に戻せない形”で安全に保存するための最重要ユーティリティです」
業務システムでは、ユーザーのパスワードを安全に扱うことが必須です。 しかし、初心者の方が最初にやってしまいがちな誤りがあります。
- パスワードをそのまま保存する(平文保存)
- SHA256 などで 1 回だけハッシュ化して保存する
- ソルトを使わない
- 全ユーザーで同じソルトを使う
これらはすべて危険です。 攻撃者がデータベースを入手した瞬間にパスワードが推測されてしまいます。
そこで登場するのが PBKDF2(Password-Based Key Derivation Function 2) です。 PBKDF2 は「ソルト」「ストレッチング」「不可逆性」を組み合わせて、 攻撃者がパスワードを推測するのを極端に難しくします。
PBKDF2 の仕組みを初心者向けにかみ砕く
PBKDF2 は次の 3 つを組み合わせた“強力な変換装置”です
- ソルト(Salt) → ランダムな追加データ。 同じパスワードでもソルトが違えばハッシュ値が変わる。
- ストレッチング(反復回数) → ハッシュ計算を何万回も繰り返す。 攻撃者の総当たり攻撃を極端に遅らせる。
- 不可逆ハッシュ(戻せない) → 暗号化ではなくハッシュ化。 元のパスワードに戻せない。
この 3 つを組み合わせることで、 攻撃者がパスワードを推測するのがほぼ不可能になります。
PBKDF2 をイメージする(初心者向け)
- パスワード
- ソルト
- 反復回数(iteration)
- ハッシュ関数(HMAC-SHA256 など)
これらをまとめて「ぐるぐる計算」して、 元に戻せない長い文字列(ハッシュ値) を作ります。
PBKDF2 を使うと何が安全になるのか?
① レインボーテーブル攻撃が無効化される
ソルトを使うことで、攻撃者が持っている「ハッシュ辞書」が使えなくなります。
② 総当たり攻撃が極端に遅くなる
ストレッチングにより、攻撃者は 1 回の試行に数万倍の時間がかかります。
③ データベースが漏洩してもパスワードは守られる
ハッシュ値とソルトが漏れても、元のパスワードは分かりません。
C# で PBKDF2 を利用する(実務向けテンプレート)
.NET 標準の PBKDF2(KeyDerivation.Pbkdf2)を使う方法です
using System;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
public static class Pbkdf2Utility
{
public static (string Hash, string Salt) HashPassword(string password)
{
// ランダムソルト生成(128bit)
byte[] salt = RandomNumberGenerator.GetBytes(128 / 8);
// PBKDF2(HMACSHA256、10万回)
string hash = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 100000,
numBytesRequested: 256 / 8));
return (hash, Convert.ToBase64String(salt));
}
public static bool VerifyPassword(string password, string storedHash, string storedSalt)
{
byte[] saltBytes = Convert.FromBase64String(storedSalt);
string hash = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: saltBytes,
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 100000,
numBytesRequested: 256 / 8));
// 固定時間比較(タイミング攻撃対策)
return CryptographicOperations.FixedTimeEquals(
Convert.FromBase64String(storedHash),
Convert.FromBase64String(hash));
}
}
C#PBKDF2 を使ったパスワード保存の流れ
登録時(Sign Up)
- ユーザーがパスワードを入力
- ソルトを生成
- PBKDF2 でハッシュ化
- ハッシュ値とソルトをデータベースに保存
保存するのはこの 2 つだけ:
| 保存するもの | 内容 |
|---|---|
| Hash | PBKDF2 の結果 |
| Salt | ランダム生成したソルト |
ログイン時(Sign In)
- ユーザーがパスワードを入力
- データベースからソルトを取得
- PBKDF2 で同じ条件でハッシュ化
- 保存されているハッシュ値と一致するか比較
- 一致すればログイン成功
PBKDF2 を使うときの「絶対にやってはいけないこと」
- ソルトを使わない
- 全ユーザーで同じソルトを使う
- SHA256 を 1 回だけハッシュ化して保存する
- ハッシュ値をログに出す
- iteration を少なくする(1000 回などは危険)
これらはすべて攻撃者に突破されます。
PBKDF2 を使うときの「実務的ベストプラクティス」
- ソルトは必ずランダム生成する
- iteration は最低 100,000 回以上
- ハッシュ値とソルトは Base64 で保存する
- 固定時間比較(FixedTimeEquals)で比較する
- パスワードは絶対に平文で保存しない
PBKDF2 と他方式の比較(初心者向け)
| 方式 | 特徴 |
|---|---|
| PBKDF2 | 標準仕様で使いやすい。企業システムで最適。 |
| bcrypt | GPU攻撃に強い。Webサービスでよく使われる。 |
| Argon2 | 最も新しく強力。メモリハードで攻撃に強い。 |
PBKDF2 は .NET 標準で使えるため、C# の業務システムでは最も現実的で安全 です。
まとめ:PBKDF2 は「ソルト+ストレッチング+不可逆性」で攻撃を防ぐ最強のユーティリティ
PBKDF2 の本質は次の 3 つです。
- ソルトで辞書攻撃を防ぐ
- ストレッチングで総当たり攻撃を遅らせる
- 不可逆ハッシュでパスワードを守る
これらを組み合わせることで、 攻撃者がパスワードを推測するのを極端に難しくします。
多くの読者のみなさんが業務システムを開発する際、 PBKDF2 を正しく使うだけでセキュリティレベルが大幅に向上し、 ユーザーの秘密を安全に守ることができます。
