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

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

「とりあえずMD5やSHA-256でハッシュ化して、ソルトを足せばいいんだよね?」

もし君がチームでそう言っているなら、今すぐそのコードを止めてほしい。残念ながら、それは「鍵のついていない金庫」を設置しているのと変わらない。攻撃者は君たちが思っている以上に賢く、そしてGPUという強力な武器をフル活用している。

今回は、現代のシステム開発において「避けては通れない」パスワードハッシュの設計と、なぜArgon2やbcryptを選ばなければならないのか、その深淵に迫る。

—

1. 攻撃者が「計算」ではなく「総当たり」を仕掛ける理由

まず、なぜSHA-256がダメなのかを理解しよう。SHA-256は「高速であること」を目的として設計されたアルゴリズムだ。セキュリティの世界では、「高速であること」は「脆弱であること」と同義だ。

攻撃者がデータベースを流出させたとき、彼らはCPUではなくGPU(NVIDIAのRTX 4090のような怪物)やFPGAをフル稼働させる。高速なハッシュ関数なら、1秒間に数十億通りのパスワード候補を試せる。数百万行のテーブルなんて、コーヒーを飲んでいる間に全滅する。

そこで登場するのが「ストレッチング」という概念だ。あえて計算を遅くすることで、攻撃者の試行効率を物理的に落とす。これがArgon2やbcryptの存在意義である。

—

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

現在、我々が選ぶべきはArgon2idだ。これには以下の理由がある。

  • メモリ耐性: CPUだけでなく、メモリの消費も強制するため、GPUやASICを使った高速並列攻撃を無効化できる。
  • サイドチャネル攻撃耐性: タイミング攻撃などに対する耐性が考慮されている。

どうしてもArgon2が使えない環境(レガシーなPHP環境など)であれば、bcryptを選択すること。これも依然として信頼できる選択肢だ。

—

3. 実装サンプル:PHPとPythonでの「鉄板」コード

「コードが複雑そう」という懸念は無用だ。標準ライブラリを使えば、驚くほどシンプルかつ堅牢な実装ができる。

PHPによる実装 (password_hash関数)

PHPには標準で強力なAPIが備わっている。自作のハッシュ関数を書くのは、セキュリティの素人がやる一番の愚行だ。

65536, // 64MBのメモリを使用
‘time_cost’ => 4, // 4回の反復計算
‘threads’ => 2, // 2スレッドで並列処理
]);

// ログイン時の検証
if (password_verify($password, $hash)) {
// 認証成功
} else {
// 認証失敗
}
?>

Pythonによる実装 (passlib + bcrypt)

Pythonの場合、passlibライブラリを使うのが実務のデファクトスタンダードだ。

from passlib.context import CryptContext

設定の定義:bcryptを使用し、ラウンド数を12に設定(十分な強度)
pwd_context = CryptContext(schemes=[“bcrypt”], deprecated=”auto”)

ハッシュ化
password = “UserSecretPassword123!”
hashed_pw = pwd_context.hash(password)

検証
if pwd_context.verify(password, hashed_pw):
print(“認証成功”)

—

4. 運用上の「盲点」:コスト設定の罠

ここで一つ、現場でよく見るミスを指摘しておく。「ストレッチング回数(コスト)を極端に低く設定したまま放置すること」だ。

インフラが強化され、サーバーのCPU性能が向上しても、昔設定した低いコストのまま運用し続けるのは危険だ。以下の運用ルールをチームに徹底してほしい。

1. コストの定期的な見直し: 年に一度、システム負荷を確認し、許容範囲内でコスト値を引き上げる。
2. ログイン時のアップグレード: ユーザーがログインしたタイミングで、古いハッシュ形式であれば再ハッシュ化して保存し直す(password_needs_rehash 関数を活用せよ)。
3. ソルトの管理: password_hashを使えばソルトは自動生成され、ハッシュ値の中に埋め込まれる。自分でソルトをDBに保存しようとして管理を複雑にするのはやめよう。

—

まとめ:エンジニアとして守るべき矜持

セキュリティは「魔法のツール」を導入すれば終わるものではない。攻撃者の視点を持ち、「もし自分が攻撃者なら、このコストをどう突破するか?」と自問自答し続けることこそが、真のエンジニアの姿だ。

今回紹介したコードは、あくまで「最低限の防御壁」だ。しかし、この基本を疎かにするシステムに、強固な防壁など築けるはずがない。

明日のコードレビューで、もし誰かが「MD5でいいんじゃない?」と言っていたら、この記事をそっと彼らの画面に共有してあげてほしい。それが、君たちのプロダクトを、そしてユーザーのデータを守る第一歩になる。

コメント

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