パスワードハッシュの「正解」はなぜ変わるのか?――その背後にある攻撃者の論理
「パスワードを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の残骸を見つけたら、それは「技術的負債」ではなく「セキュリティの時限爆弾」ですよ。
コメント