C# Tips | セキュリティ:PBKDF2を利用する

C# C#
スポンサーリンク
スポンサーリンク

PBKDF2 を利用することは「パスワードを“絶対に戻せない形”で安全に保存するための最重要ユーティリティです」

業務システムでは、ユーザーのパスワードを安全に扱うことが必須です。 しかし、初心者の方が最初にやってしまいがちな誤りがあります。

  • パスワードをそのまま保存する(平文保存)
  • SHA256 などで 1 回だけハッシュ化して保存する
  • ソルトを使わない
  • 全ユーザーで同じソルトを使う

これらはすべて危険です。 攻撃者がデータベースを入手した瞬間にパスワードが推測されてしまいます。

そこで登場するのが PBKDF2(Password-Based Key Derivation Function 2) です。 PBKDF2 は「ソルト」「ストレッチング」「不可逆性」を組み合わせて、 攻撃者がパスワードを推測するのを極端に難しくします。

PBKDF2 の仕組みを初心者向けにかみ砕く

PBKDF2 は次の 3 つを組み合わせた“強力な変換装置”です

  1. ソルト(Salt) → ランダムな追加データ。 同じパスワードでもソルトが違えばハッシュ値が変わる。
  2. ストレッチング(反復回数) → ハッシュ計算を何万回も繰り返す。 攻撃者の総当たり攻撃を極端に遅らせる。
  3. 不可逆ハッシュ(戻せない) → 暗号化ではなくハッシュ化。 元のパスワードに戻せない。

この 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)

  1. ユーザーがパスワードを入力
  2. ソルトを生成
  3. PBKDF2 でハッシュ化
  4. ハッシュ値とソルトをデータベースに保存

保存するのはこの 2 つだけ:

保存するもの内容
HashPBKDF2 の結果
Saltランダム生成したソルト

ログイン時(Sign In)

  1. ユーザーがパスワードを入力
  2. データベースからソルトを取得
  3. PBKDF2 で同じ条件でハッシュ化
  4. 保存されているハッシュ値と一致するか比較
  5. 一致すればログイン成功

PBKDF2 を使うときの「絶対にやってはいけないこと」

  • ソルトを使わない
  • 全ユーザーで同じソルトを使う
  • SHA256 を 1 回だけハッシュ化して保存する
  • ハッシュ値をログに出す
  • iteration を少なくする(1000 回などは危険)

これらはすべて攻撃者に突破されます。

PBKDF2 を使うときの「実務的ベストプラクティス」

  • ソルトは必ずランダム生成する
  • iteration は最低 100,000 回以上
  • ハッシュ値とソルトは Base64 で保存する
  • 固定時間比較(FixedTimeEquals)で比較する
  • パスワードは絶対に平文で保存しない

PBKDF2 と他方式の比較(初心者向け)

方式特徴
PBKDF2標準仕様で使いやすい。企業システムで最適。
bcryptGPU攻撃に強い。Webサービスでよく使われる。
Argon2最も新しく強力。メモリハードで攻撃に強い。

PBKDF2 は .NET 標準で使えるため、C# の業務システムでは最も現実的で安全 です。

まとめ:PBKDF2 は「ソルト+ストレッチング+不可逆性」で攻撃を防ぐ最強のユーティリティ

PBKDF2 の本質は次の 3 つです。

  • ソルトで辞書攻撃を防ぐ
  • ストレッチングで総当たり攻撃を遅らせる
  • 不可逆ハッシュでパスワードを守る

これらを組み合わせることで、 攻撃者がパスワードを推測するのを極端に難しくします。

多くの読者のみなさんが業務システムを開発する際、 PBKDF2 を正しく使うだけでセキュリティレベルが大幅に向上し、 ユーザーの秘密を安全に守ることができます。

タイトルとURLをコピーしました