C# Tips | セキュリティ:パスワードを安全にHashする

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

パスワードの安全なハッシュ化は「ユーザーの秘密を守るための最重要セキュリティ基盤です」

パスワードを安全に扱うことは、業務システムにおけるセキュリティの最重要ポイントです。 初心者の方でも誤解しやすいのですが、パスワードをそのまま保存する(平文保存)ことは絶対にしてはいけません。 万が一データベースが漏洩した場合、すべてのユーザーのパスワードが攻撃者に丸見えになってしまいます。

そのため、パスワードは必ず ハッシュ化(不可逆変換)+ソルト(Salt)+ストレッチング(Stretching) を組み合わせて安全に保存します。 ここでは、初心者にも分かりやすいように、仕組み・実務で使えるコード例・テンプレートを丁寧に解説します。

ハッシュ化とは何か?不可逆変換でパスワードを守る技術です

ハッシュ化は「元に戻せない変換」です

ハッシュ化とは、パスワードを特殊な計算式で「まったく別の文字列」に変換する技術です。 最大の特徴は 元に戻せない(不可逆性) ことです。

例: password123a58f9c2d...(元に戻せない)

これにより、データベースが漏洩しても攻撃者は元のパスワードを知ることができません。

暗号化とハッシュ化の違いを理解することが重要です

暗号化は「鍵があれば戻せる」、ハッシュ化は「戻せない」

  • 暗号化(Encryption) → 鍵があれば元に戻せる(復号できる)
  • ハッシュ化(Hashing) → 元に戻せない(不可逆)

パスワードは「戻す必要がない」ため、ハッシュ化が適しています。

ソルト(Salt)とは?辞書攻撃を防ぐための“塩”です

同じパスワードでも異なるハッシュ値にする仕組みです

ハッシュ化には弱点があり、同じ文字列は必ず同じハッシュになります。 攻撃者は「よく使われるパスワードのハッシュ一覧(レインボーテーブル)」を持っているため、照合されると簡単に突破されます。

そこで ソルト(Salt) を使います。

例: パスワード:mysecret ソルト:xyz987mysecretxyz987 をハッシュ化する

ユーザーごとに異なるソルトを使うことで、同じパスワードでもハッシュ値が変わり、辞書攻撃が無効化されます。

ストレッチング(Stretching)とは?計算をわざと重くして攻撃を防ぐ技術です

ハッシュ計算を数千〜数万回繰り返して攻撃を困難にします

コンピューターは高速なので、ハッシュ化を何億回も試す総当たり攻撃が可能です。 そこで、ハッシュ計算を 何千回・何万回も繰り返す(ストレッチング) ことで攻撃を困難にします。

ユーザーのログインでは数ミリ秒〜数秒の遅延は問題ありませんが、攻撃者にとっては膨大な計算量になります。

C# で安全にパスワードをハッシュ化する方法(PBKDF2)

PBKDF2 は .NET 標準で使える安全なハッシュ方式です

C# では、PBKDF2(RFC 2898)を使って安全にパスワードをハッシュ化できます。 Microsoft 公式ドキュメントでも PBKDF2 の利用例が紹介されています。

実務で使える「安全なパスワードハッシュユーティリティ」テンプレート

ソルト生成+PBKDF2+Base64 で保存する実務向けテンプレートです

using System;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;

public static class PasswordHashUtility
{
    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#

使い方:

var (hash, salt) = PasswordHashUtility.HashPassword("MyPassword123");
bool ok = PasswordHashUtility.VerifyPassword("MyPassword123", hash, salt);

Console.WriteLine(ok); // true
C#

ここでの重要ポイントは:

  • ソルトは毎回ランダム生成する
  • ハッシュ値とソルトは両方データベースに保存する
  • 固定時間比較でタイミング攻撃を防ぐ
  • PBKDF2 の反復回数は 100,000 回以上が推奨される(2026 年時点)

bcrypt / Argon2 を使う選択肢もあります(より強力)

bcrypt や Argon2 はパスワード専用に設計された強力なハッシュ方式です

.NET では PBKDF2 が標準ですが、 外部ライブラリを使えば bcrypt や Argon2 も利用できます。

これらは「計算を重くする」ことに特化しており、総当たり攻撃に強いです。

パスワードハッシュ化で絶対にやってはいけないこと

以下はすべて危険です。

  • 平文で保存する
  • reversible encryption(復号できる暗号化)で保存する
  • SHA-256 単体でハッシュ化する(高速すぎて危険)
  • ソルトを使わない
  • 全ユーザーで同じソルトを使う

これらは攻撃者にとって突破しやすく、実務では絶対に避けるべきです。

まとめ:安全なパスワードハッシュは「ソルト+ストレッチング+不可逆性」が必須です

パスワードハッシュ化の本質は、

  • 元に戻せないハッシュ化(不可逆性)
  • ユーザーごとのランダムソルト
  • 計算を重くするストレッチング(PBKDF2 / bcrypt / Argon2)
  • 固定時間比較でタイミング攻撃対策

を組み合わせて、攻撃者が突破できないようにすることです。

多くの購読者のみなさんが業務システムを開発する際、 この「安全なパスワードハッシュユーティリティ」を導入するだけで、 セキュリティレベルが大幅に向上し、 データ漏洩時の被害を最小限に抑えることができます。

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