【実務・中級編】安全なパスワードハッシュ化アルゴリズム (Argon2, bcrypt) – アプリケーションセキュリティ & 安全な開発防御ガイド

パスワードハッシュの「正解」はなぜ変わるのか?――その背後にある攻撃者の論理

「パスワードをMD5でハッシュ化して保存しています」
もし後輩がコードレビューでこんなことを言ってきたら、私は迷わずそのキーボードを取り上げます。なぜなら、それは「鍵のかかっていない家の玄関に『この中は無人です』という張り紙をしている」のと同じだからです。

今日、我々が扱うのは単なる「パスワードの保存方法」ではありません。GPUやFPGAをフル稼働させ、1秒間に数千億回ものハッシュ試行を行う攻撃者たちを、いかにして「計算資源の無駄遣い」で追い返すかという、泥臭い戦争の話です。

—

1. なぜMD5やSHA-1は「死んだ」のか

かつて主流だったMD5やSHA-1は、暗号学的ハッシュ関数としては優秀ですが、「高速であること」が最大の脆弱性です。

攻撃者は、流出したデータベースを入手すると、クラウド上のGPUクラスタを使い、辞書攻撃やレインボーテーブル攻撃を仕掛けます。MD5であれば、現代のPC1台でも1秒間に数十億通りのハッシュ計算が可能です。つまり、複雑なパスワードであっても、数時間で解読されてしまう。

これに対抗するには、「あえて計算を遅くする」アルゴリズムを選ぶしかありません。

—

2. 推奨アルゴリズム:Argon2idの選択

現在、我々が採用すべきは Argon2id です。これは2015年のパスワードハッシュコンペ(PHC)で優勝したアルゴリズムで、以下の3つの耐性を持っています。

1. 時間耐性: 計算に時間がかかる(攻撃コストの増大)。
2. メモリ耐性: 大量のメモリを消費する(GPU/ASICによる高速化を阻害)。
3. サイドチャネル攻撃耐性: メモリへのアクセスパターンが一定で、タイミング攻撃を防ぐ。

もしArgon2idが利用できない環境(古いライブラリ等)であれば、次点で bcrypt を選んでください。bcryptは長年使われており、その堅牢性は証明済みです。

—

3. 実践:セキュアな実装サンプル

言語ごとのモダンな実装例です。これらは「ソルト(Salt)」の生成も自動的に行い、適切なハッシュ値に埋め込んでくれます。

PHP (password_hash関数)

PHPは標準で非常に強力なハッシュAPIを持っています。これを使わない手はありません。

65536, // 64MBのメモリ消費
‘time_cost’ => 4, // 4回の反復計算
‘threads’ => 2 // 並列スレッド数
];

$hash = password_hash($password, PASSWORD_ARGON2ID, $options);

// 検証時
if (password_verify($password, $hash)) {
echo “ログイン成功”;
} else {
echo “認証失敗”;
}

Python (Argon2-cffi)

Pythonでは標準ライブラリではなく、argon2-cffiライブラリを使うのが業界標準です。

from argon2 import PasswordHasher

初期化(デフォルト設定がすでに十分セキュア)
ph = PasswordHasher()

ハッシュ化
password = “UserSecretPassword123!”
hash_value = ph.hash(password)

検証
try:
ph.verify(hash_value, password)
print(“ログイン成功”)
except Exception:
print(“認証失敗”)

—

4. 運用で陥る「計算コスト」の罠

ここで注意すべきは「計算コスト(Work Factor)」の設定です。

  • 低すぎると: 攻撃者が容易にパスワードを特定します。
  • 高すぎると: サーバーのCPU負荷が跳ね上がり、ログイン処理だけでDoS攻撃を受けているような状態になります。

ベストプラクティス:
1. ベンチマークを取る: ターゲットの環境で「認証に0.2秒〜0.5秒かかる」程度の設定を探ってください。ユーザー体験を損なわず、攻撃者に最大の苦痛を与えるスイートスポットです。
2. 定期的な再ハッシュ: ハッシュアルゴリズムの脆弱性は数年で変わります。ユーザーがログインしたタイミングで、パスワードを新しいコスト設定で再ハッシュして保存し直す「アップグレード戦略」を実装してください。

—

5. 最後に:インフラ屋として伝えたいこと

コードを完璧に書いても、データベースそのものが流出したら終わりです。

  • DBの暗号化: TDE(透過的データ暗号化)を有効にする。
  • アクセス制御: アプリケーションサーバーからDBサーバーへの通信は、IAMロールまたはファイアウォールで厳密に制限する。
  • ログの秘匿: ログファイルにパスワード(ハッシュ値すら)を絶対に出力させない。

セキュリティとは、一つの壁を築くことではなく、「攻撃者が諦めるまでの時間を、いかに引き延ばすか」という持久戦です。今日紹介したArgon2idへの移行は、その戦いにおいて極めて強力な武器になります。

さあ、今すぐプロジェクトのコードを見直しましょう。古いMD5の残骸を見つけたら、それは「技術的負債」ではなく「セキュリティの時限爆弾」ですよ。

コメント

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