bcrypt と Argon2:パスワードハッシュ設定の選び方
bcrypt と Argon2 を比較:セキュリティ特性、実運用でのパフォーマンスコスト、そして現代的なバックエンドで安全なパラメータを選ぶ方法をわかりやすく解説します。

パスワードハッシュが解く問題とは
パスワードハッシュは、バックエンドがパスワードそのものを保存せずに済むようにします。誰かがサインアップするとき、サーバーはパスワードを一方向関数に通して結果(ハッシュ)を保存します。ログイン時にはユーザーが入力したパスワードをハッシュ化し、保存された値と照合します。
ハッシュは暗号化ではありません。復号する方法はありません。この一方向性が、パスワードにハッシュを使う理由です。
では、なぜ SHA-256 のような高速ハッシュを使わないのでしょうか?攻撃者にとって「高速」は望ましい性質だからです。データベースが流出した場合、攻撃者は1回ずつログインを試すのではなく、流出したハッシュリストを使ってオフラインで可能な限り高速に推測を行います。GPU を使えば非常に大規模に試すことができます。ユニークなソルトがあっても、高速ハッシュは総当たりに対して安価です。
現実的な失敗例はこうです:小さなウェブアプリがユーザーテーブルを流出させ、攻撃者がメールアドレスとハッシュを手に入れる。もしそのハッシュが高速な関数で作られていれば、一般的なパスワードやその変種はすぐに割られてしまいます。攻撃者は同じパスワードを他のサイトで試したり(クレデンシャルスタッフィング)、あなたのアプリ内で上位権限を得るために使ったりします。
良いパスワードハッシュは推測を高コストにします。目的は「破れないこと」ではなく「試す価値がないほど遅く高コストにすること」です。
パスワードハッシュのセットアップは以下を満たすべきです:
- 一方向である(復元ではなく検証する)
- 推測ごとに遅い
- 並列化ハードウェア(特にGPU)に対して高コストになる
- 実際のログインでは十分に速く感じられる
- 時間とともにコストを上げられるよう調整可能である
bcrypt と Argon2 を一言で
bcrypt と Argon2 を比べるということは、データベース流出後にパスワード推測をどのように遅らせるかを選ぶことです。
bcrypt は古くから広くサポートされている選択肢です。CPU を集中的に使うよう設計されており、主な調整点はコストファクターだけです。ライブラリが豊富で導入が簡単、挙動も予測しやすいという意味で“退屈”であることが利点です。
Argon2 はより新しく、メモリハード性を念頭に設計されています。各推測に意味のある量のRAMを使わせることで、GPU や専用ハードで大規模な並列推測をする攻撃の効果を下げられます。
Argon2 には3つのバリアントがあります:
- Argon2i:一部のサイドチャネル攻撃への耐性を重視
- Argon2d:GPU 耐性を重視(サイドチャネル考慮は少なめ)
- Argon2id:実用的な折衷で、パスワードハッシュの一般的なデフォルト
スタックが Argon2id をサポートし、安全にメモリをチューニングできるなら、通常は最良の現代的デフォルトです。古いシステムとの互換性が最優先なら、bcrypt も適切に設定すれば堅実な選択です。
重要なセキュリティ特性
核心は単純です:攻撃者がパスワードデータベースを盗んだ場合、スケールで推測するのにどれだけコストがかかるか。
bcrypt はコスト(ワークファクター)を制御します。コストを上げれば各試行にかかる時間が伸びます。それにより攻撃者は遅くなりますが、ログイン検証の遅延も増えるため、ユーザーにとって許容できる範囲で調整する必要があります。
Argon2id では、時間コストに加えてメモリハードネスを付与できます。各試行がCPU時間と特定のパターンでアクセスするRAMを必要とするため、GPU は並列計算での優位性を失いやすくなります。
ソルトは必須です。各パスワードに対して一意でランダムなソルトを使うことで:
- 事前計算表がデータベース全体で再利用されるのを防ぐ
- 同じパスワードがユーザー間で同一のハッシュにならない
ソルトは弱いパスワードを強くはしません。主に流出後に攻撃者にユーザーごとに計算作業を強いるためのものです。
bcrypt の強みと制限
bcrypt は導入が容易で広く使われています。互換性が必要な場合や、暗号ライブラリが限られているスタック、シンプルな調整レバーが欲しい場合に適しています。
最大の注意点は72バイトのパスワード制限です。bcrypt は最初の72バイトしか使用せず、それ以降は無視します。長いパスフレーズやパスワードマネージャーを使う場合に驚きが生じる可能性があります。
bcrypt を選ぶなら、パスワード長の扱いを明示してください。バイト単位で最大長を設けるか、長い入力をすべてのサービスで一貫した方法で処理するようにします。ユーザーが期待するパスワードと実際に使われるものがずれないようにするのが重要です。
bcrypt はメモリハードなオプションほど並列クラッキングに強くはありません。防御は有効ですが、各試行を高コストに保つために適切なコストファクターの選択に依存します。
新しいシステムを構築する場合や高価値アカウントがある場合(有料プランや管理者権限など)は、新しいハッシュを Argon2id で作成しつつ既存の bcrypt ハッシュはログイン時に受け入れる、という移行が一般的でリスクが低いです。
Argon2 の強みとトレードオフ
Argon2 はパスワードハッシュ向けに設計されました。Argon2id は多くのチームが選ぶバリアントで、GPU 耐性とサイドチャネル対策のバランスが取れています。
Argon2id は3つのパラメータを持ちます:
- Memory (m):ハッシュ実行中に使うRAM量
- Time/iterations (t):そのメモリ上を何回パスするか(イテレーション数)
- Parallelism (p):いくつのレーンを使うか(マルチコアでの効果)
メモリが主な利点です。各試行が意味のある量のRAMを必要とするなら、攻撃者は並列で実行できる試行数を抑えられ、RAMや帯域に大きなコストを払う必要があります。
欠点は運用面です:ハッシュごとのメモリを増やすと同時に処理できるログイン数が減り、ピーク時にキューやタイムアウト、最悪の場合はメモリ不足を起こす可能性があります。多くの同時ログインを許すと資源問題になることもあります。
Argon2id を安全かつ使いやすくするには、パフォーマンス機能としてチューニングしてください:
- 本番に近いハードでベンチマークする
- 同時ハッシュ作業を制限する(ワーカーの上限、キュー)
- ログイン試行にレート制限を設け、失敗の繰り返しをロックする
- 設定をサービス間で一貫させ、弱いエンドポイントが標的にならないようにする
実際のウェブバックエンドでのパフォーマンスコスト
パスワードハッシュでは「より速い方が良い」という考えは通常誤りです。攻撃者にとって高コストにしつつ、実際のログインが遅く感じないバランスを取ることが重要です。
実用的な設定方法は、本番のようなハードウェアで検証あたりの時間予算を決めることです。多くのチームは検証あたり100〜300msを目安にしますが、正しい値はトラフィックとサーバー構成によります。bcrypt と Argon2 の違いは、何にコストを払っているかです:bcrypt は主にCPU時間、Argon2 はメモリも予約します。
目標時間を決めて測る
目標のハッシュ時間を選び、本番に近い条件でテストしてください。サインアップやパスワード変更時のハッシュと、ログイン検証(ホットパス)を測ることが重要です。
簡単な測定計画の例:
- 同時1、10、50のログイン検証をテストし、p50 と p95 のレイテンシを記録する
- キャッシュやCPUブーストのノイズを減らすために複数回実行する
- データベース呼び出しを別に測定し、実際のハッシュコストを把握する
- デプロイするコンテナと CPU 制限でテストする
スパイクが平均より重要
多くのシステムはピーク時に失敗します。マーケティングのメールで一斉にログインが発生した場合、ハッシュ設定が応答性を決めます。
例えば、1回の検証が250msで、サーバーが並列で40件処理できるとすると、500件のログインの波で数秒の待ち時間が発生します。その場合、コストを少し下げて厳格なレート制限を組み合わせる方が、ハッシュを極端に重くしてログインエンドポイントを脆弱にするよりも現実的に安全を高めることがあります。
対話的ログインを予測可能に保つ
すべてのパスワード操作が同じ緊急度である必要はありません。対話的なログインは一定のコストに保ち、重い作業はクリティカルパスの外で行うのが一般的です。よくあるパターンは rehash-on-login(ログイン成功後にハッシュを新しいポリシーで更新)や、マイグレーションをバックグラウンドジョブで実行する方法です。
パラメータ選びの手順
パラメータ調整は、攻撃者のコストを上げつつ、サインインが遅くなりすぎたりサーバーが不安定になったりしないようにすることです。
-
スタックでよくサポートされているアルゴリズムを選ぶ。 Argon2id が利用可能でサポートが十分なら通常はデフォルトにします。互換性が重要なら bcrypt でも問題ありません。
-
本番に近いハードで検証あたりの目標時間を設定する。 ピーク時にログインがスムーズに感じられる値を選んでください。
-
その時間に合わせてチューニングする。 bcrypt ならコストファクターを調整、Argon2id ならメモリ、イテレーション、並列性をバランスさせます。メモリが攻撃者経済性に最も影響を与えるレバーです。
-
アルゴリズムと設定をハッシュと一緒に保存する。 標準的なハッシュフォーマットの多くはこれを埋め込みます。データベースのフィールド長も十分にして、ハッシュが切れないようにします。
-
re-hash-on-login でのアップグレードを計画する。 ユーザーがログインしたときに、保存されているハッシュの設定が現在のポリシーより弱ければ新しい設定で再ハッシュして置き換えます。
実用的な出発点
測定を始める前に保守的な出発点を設定して調整しましょう。
- bcrypt では、多くのチームがコスト12程度から始め、実測に基づいて調整します。
- Argon2id では、メモリを数十〜数百MB、タイムコストを2〜4、並列性を1〜2あたりから始めることが一般的です。
これらは出発点であり固定規則ではありません。適切な設定はトラフィック、ハードウェア、ピーク負荷に合うものです。
パスワード保存を弱めるよくあるミス
パスワード保存の失敗の多くは設定の穴から生じ、アルゴリズム自体が壊れているわけではありません。
ソルトのミスは大きな問題です。各パスワードに一意のソルトを保存せずに使い回すと、攻撃者が作業を再利用しやすくなります。
コストを見直さないこともよくあります。開発時に低いコストで出荷してしまい、その後見直さないと、ハードウェアが向上して攻撃者側で安価になってしまいます。
Argon2 の過剰チューニングも一般的です。メモリを極端に上げると見た目は良くても、実際にはログインが遅くなったりバックログが発生したり、ピーク時にメモリ不足を起こしたりします。
パスワード長の扱いも重要です。特に bcrypt の72バイト制限を知らずに長いパスワードを黙って切り捨てると、ユーザーにとって混乱の元になります。
いくつかの実践的な習慣:
- パスワードごとに一意のソルトを使う(ライブラリに生成させる)
- ロードテストを行い、設定を定期的に見直す
- Argon2 のメモリは単一ログインのベンチマークではなくピークトラフィックに合わせて調整する
- パスワード長の制限を明示し、一貫して扱う
- ログインエンドポイントに同時実行制限と監視を置く
安全なセットアップの簡単チェックリスト
リリース時やインフラ変更時にこの短いチェックリストを参照してください:
- パスワードごとに一意のソルトをランダムに生成してハッシュと一緒に保存する
- ピークトラフィックに耐えるハッシュコストをロードテストで確認する
- ハッシュと一緒にパラメータを保存して、古いアカウントも検証できるようにする
- オンライン攻撃対策(レート制限や短いロックアウト)を設ける
- アップグレードパス(通常は rehash-on-login)を用意する
簡単なサニティチェック:ステージングで成功・失敗を混ぜたログインのバーストテストを行い、エンドツーエンドのレイテンシとCPU、RAMの使用状況を監視してください。ログイン経路が苦しむなら、コストを下げるかレート制限を強化して調整し、ソルトなどの必須要素を省略して問題を“修正”しないでください。
現実的な例:小規模ウェブアプリ向けチューニング
数千人規模のユーザーを持つ小さなSaaSアプリを想像してください。日中は安定していますが、ニュースレター直後や業務開始時に短時間のログインバーストがあります。ここで選択がキャパシティ設計に直結します。
オフラインクラックのコストを上げるために Argon2id を選びます。実際のサーバーで検証あたりの目標時間(例:100〜250ms)を決め、メモリ設定を見ながらその時間を達成するように調整します。メモリ設定は同時に処理できるログイン数に影響するので注意してください。
実用的なチューニングループは以下の通りです:
- 控えめなイテレーションと並列性で始める
- 同時処理が不快になるまでメモリを増やす
- 時間コストを微調整するためにイテレーションを調整する
- 単一リクエストだけでなくバーストをシミュレートして再テストする
既に弱めの設定で作られた古いハッシュがあるなら、それらを検証しつつ静かにアップグレードします。ログイン成功時に再ハッシュして保存することで、強化は段階的に進みます。
リリース後はログインを他の重要エンドポイントと同様に監視してください:p95/p99 レイテンシ、バースト時のCPUとRAM、失敗ログインの急増、そして古いハッシュがどれだけ早く置き換えられているかを追跡します。
次のステップ:安全に出荷し改善を続ける
ポリシーを書面化し、それを生きた設定として扱ってください。例えば「Argon2id: メモリ X、イテレーション Y、並列性 Z」や「bcrypt コスト N」と、選定日と見直し日(6〜12か月ごとが目安)を記録します。
アップグレードパスを用意しておけば古いハッシュに縛られません。re-hash-on-login は簡単で多くのシステムでうまく機能します。
強力なハッシュは重要ですが、オンラインの悪用対策に代わるものではありません。レート制限、ロックアウト、慎重なパスワードリセットフローも現実的なセキュリティでは同じくらい重要です。
もし AppMaster のようなノーコードプラットフォームでバックエンドを作るなら、認証モジュールが強力なパスワードハッシュをデフォルトで使い、あなたがデプロイするインフラと同種の環境でコストがチューニングされているか確認する価値があります。こうした小さな事前のテストが「安全で使いやすい」と「負荷で使えない」の差を生みます。
よくある質問
パスワードハッシュは、実際のパスワードを保存せずにログインを検証できるようにします。ハッシュ(不可逆な値)を保存し、ユーザーの入力をハッシュ化して比較します。もしデータベースが流出しても、攻撃者はパスワードを直接読み取れず、当て推量で推測する必要があります。
暗号化は復号可能で、鍵が漏れたり適切に管理されていなければ元のパスワードが復元されます。ハッシュは一方向性なので、保存した値を“復号”して元のパスワードに戻すことはできません。
SHA-256 のような高速ハッシュは攻撃者に有利です。データを盗まれた場合、攻撃者はオフラインで大量に推測を試み、特にGPUを使うと非常に高速になります。パスワードハッシュは意図的に遅く(できればメモリ集約的に)することで、大規模な総当たりを高コストにします。
ソルトは各パスワードに付けるランダムで一意の値で、ハッシュと一緒に保存します。これにより同じパスワードが異なるユーザーで同じハッシュにならず、事前計算された表(レインボーテーブル)の再利用を防ぎます。ただし、ソルト自体が弱いパスワードを強くするわけではありません。
Argon2id は並列クラッキングに対する耐性を持たせやすい設計で、メモリをチューニングできるなら多くの場合デフォルトとして適しています。互換性が最優先で古いシステムを広くサポートする必要があるなら、bcrypt を選び、十分に高いコストファクターを設定してください。
bcrypt には72バイトの制限があります:最初の72バイトしか使われず、それ以降は無視されます。長いパスフレーズやパスワードマネージャーを使う場合は注意が必要です。バイト単位での最大長を明示するか、長い入力を一貫した方法で扱ってサイレントな切り捨てを避けてください。
Argon2id で最も重要なのはメモリです。メモリを増やすと並列で試せる推測数が制限され、攻撃者はRAMと帯域にコストを払わなければならなくなります。ただし、メモリを増やしすぎると同時ログイン数が減り、サーバー側で問題が出るため、ピーク時のトラフィックに合わせて調整してください。
実際にデプロイするハードウェア上で予測可能な検証時間を目標にしてください。多くのチームは検証あたり100〜300ms程度を目安にしていますが、重要なのは同時実行時の挙動です。負荷テストでピーク時の応答性を確認しましょう。
ハッシュに使ったアルゴリズムとそのパラメータをハッシュと一緒に保存しておけば、古いユーザーはそのまま検証できます。一般的な方法は rehash-on-login:ログイン成功時に、保存されているハッシュが現在のポリシーより弱ければ新しい設定で再ハッシュして置き換えます。
よくある失敗例は、ソルトを使わない/使い回す、デフォルトでコストを低くして見直さない、Argon2 を過剰にチューニングしてピーク時にログインがタイムアウトする、そして bcrypt の長さ処理を見落とすことです。ログインエンドポイントにはレート制限や短いロックアウトを設けましょう。


