「パスワードはハッシュ化して保存しているから安全」——そう思っているなら注意が必要です。単純なハッシュ化だけでは、「レインボーテーブル攻撃」によってパスワード候補を推測される可能性があります。
レインボーテーブル(Rainbow Table)とは、ハッシュ値から元のパスワード候補を効率的に探すために、ハッシュ関数と還元関数を使ったチェーンの始点・終点を事前計算して保存しておくデータ構造です。単純にすべてのパスワードとハッシュ値を保存する表ではなく、保存容量を抑えながら逆引きの成功率を高める「時間・メモリのトレードオフ」を利用しています。
レインボーテーブルを使った攻撃をレインボーテーブル攻撃と呼びます。特に、ソルトなしでMD5やSHA-1などの高速な汎用ハッシュ関数を使って保存された短く単純なパスワードは、辞書攻撃や総当たり攻撃、レインボーテーブル攻撃によって推測されるリスクが高くなります。
本記事では、レインボーテーブルの仕組み、ハッシュ化の基礎、辞書攻撃・ブルートフォース攻撃との違い、実際の攻撃手順、ソルト、ペッパー、ストレッチング、Argon2id・bcrypt・PBKDF2による対策、開発者向けの実装方法、被害・注意事例、FAQまで解説します。
レインボーテーブルとは?
レインボーテーブル(Rainbow Table)とは、ハッシュ値から元のパスワード候補を効率的に探すために、事前計算されたチェーンの始点と終点を保存しておくデータ構造です。
レインボーテーブルは、Philippe Oechslin氏が提案した時間・メモリのトレードオフを利用した手法として知られています。すべてのパスワードとハッシュ値をそのまま保存すると巨大な容量が必要になりますが、レインボーテーブルではハッシュ関数と還元関数を使ったチェーンを作り、その始点と終点を保存することで、保存容量を抑えながらハッシュ値からパスワード候補を探せるようにします。

ハッシュ化の基礎と弱点
パスワードのハッシュ化とは、パスワードをハッシュ関数に通して、固定長の文字列であるハッシュ値に変換することです。代表的なハッシュ関数には、MD5、SHA-1、SHA-256、SHA-512などがあります。
ハッシュ化には、以下のような特徴があります。
- 一方向性:ハッシュ値から元のパスワードを直接計算することは困難
- 決定性:同じ入力は常に同じハッシュ値になる
- 高速性:汎用ハッシュ関数は高速に計算できる
このうち、パスワード保存で問題になりやすいのが「決定性」と「高速性」です。同じパスワードが常に同じハッシュ値になるため、攻撃者が事前に大量の候補パスワードのハッシュ値を計算しておけば、流出したハッシュ値と照合できます。また、MD5やSHA-1、SHA-256のような汎用ハッシュ関数は高速に計算できるため、総当たり攻撃や辞書攻撃にも弱くなります。
password → 5f4dcc3b5aa765d61d8327deb882cf99
123456 → e10adc3949ba59abbe56e057f20f883e
qwerty → d8578edf8458ce06fbc5bb76a58c5ca4
レインボーテーブル攻撃と他の攻撃手法の違い
レインボーテーブル攻撃は、パスワード候補をリアルタイムで計算する攻撃とは異なり、事前計算したデータを利用する点が特徴です。
| 攻撃手法 | 仕組み | 特徴 | 弱点 |
|---|---|---|---|
| ブルートフォース攻撃 | すべての文字の組み合わせを試し、リアルタイムでハッシュ計算して照合する | 事前準備は少ないが、文字数や文字種が増えると計算量が急増する | 長く複雑なパスワードに弱い |
| 辞書攻撃 | よく使われる単語や漏えいパスワードリストを使い、ハッシュ計算して照合する | 人間が使いがちなパスワードに強い | ランダムで長いパスワードには弱い |
| レインボーテーブル攻撃 | 事前に作成したチェーンテーブルを使い、ハッシュ値からパスワード候補を探す | テーブルに含まれる範囲では高速に候補を探せる | ユーザーごとの十分なソルトがあると既製テーブルが使いにくくなる |
ブルートフォース攻撃は、メモリ使用量は少ない一方で、試行のたびにハッシュ計算が必要です。レインボーテーブルは、事前計算したチェーンを保存しておくことで、照合時の計算時間を減らします。その代わり、テーブル作成に時間と保存容量が必要になります。これは「時間とメモリのトレードオフ」と呼ばれます。
レインボーテーブル攻撃の実際の手順
レインボーテーブル攻撃は、一般に以下のような流れで行われます。
- ハッシュ値の入手:データベースの不正取得、SQLインジェクション、設定ミスなどにより、ユーザーのパスワードハッシュを入手する
- 対象アルゴリズムの確認:MD5、SHA-1、SHA-256など、どのハッシュアルゴリズムが使われているかを推測・確認する
- レインボーテーブルの準備:対象アルゴリズムや文字種、文字数に対応したレインボーテーブルを用意する
- テーブルとの照合:入手したハッシュ値をもとに、チェーンをたどって該当するパスワード候補を探す
- 候補パスワードの検証:見つかった候補を実際にハッシュ化し、流出ハッシュと一致するか確認する
MD5やSHA-1は高速に計算できる汎用ハッシュ関数であり、パスワード保存には適していません。特に、ソルトなしで保存された短く単純なパスワードは、辞書攻撃、総当たり攻撃、レインボーテーブル攻撃によって推測されるリスクが高くなります。「password」や「123456」のような一般的なパスワードは、オンラインのハッシュ逆引きサービスや既存のデータセットで見つかる場合があります。
レインボーテーブル攻撃への対策

ソルト(Salt)の追加
ソルト(Salt)とは、ハッシュ計算の前にパスワードへ付加するランダムな文字列です。ユーザーごと、パスワードごとに異なるランダムなソルトを使うことで、同じパスワードでも異なるハッシュ値になります。
ソルトは秘密情報ではなく、通常はハッシュ値と一緒に保存されます。重要なのは、ユーザーごと・パスワードごとに十分にランダムで一意なソルトを使うことです。
ソルトなし:password → 5f4dcc3b5aa765d61d8327deb882cf99
ソルトあり:password + ランダムソルト → ソルトごとに異なるハッシュ値ソルトを使うと、攻撃者は既製のレインボーテーブルをそのまま使いにくくなります。ユーザーごとに異なるソルトが使われるため、攻撃者は各ソルトに対応するテーブルを個別に作り直す必要があり、攻撃コストが大きく増加します。
ストレッチング(Key Stretching)
ストレッチングとは、ハッシュ計算を何度も繰り返すことで、1回のパスワード試行にかかる計算コストを意図的に増やす手法です。攻撃者が総当たり攻撃や辞書攻撃を行う際の試行回数を減らしにくくする効果があります。
- 目的:1回のパスワード検証にあえて時間をかけ、攻撃者の大量試行を困難にする
- 効果:レインボーテーブル作成や総当たり攻撃にかかるコストを増やす
- 注意点:コストを高くしすぎると、正規ユーザーのログイン処理やサーバー負荷にも影響する
ペッパー(Pepper)の活用
ペッパーとは、パスワードハッシュに追加で使う秘密値です。ソルトと違い、ペッパーはデータベースには保存せず、アプリケーション設定、環境変数、KMS、HSMなど別の場所で管理します。
データベースだけが流出した場合でも、攻撃者がペッパーを知らなければパスワード推測の難度を高められます。ただし、ペッパーが漏えいした場合のローテーションや、アプリケーション全体への影響を考慮して設計する必要があります。
安全なパスワードハッシュアルゴリズムの使用
MD5、SHA-1、SHA-256、SHA-512などの汎用ハッシュアルゴリズムは、パスワード保存のために設計されたものではありません。パスワード保存には、意図的に計算コストを高められる専用のパスワードハッシュアルゴリズムを使用する必要があります。
| アルゴリズム | 特徴 | 推奨度 | 備考 |
|---|---|---|---|
| Argon2id | メモリ・CPU・並列度を調整できる現代的なパスワードハッシュ | ✅ 新規実装で推奨 | OWASPでも推奨される有力な選択肢。適切なパラメータ設定が必要 |
| bcrypt | 長年使われている実績あるパスワードハッシュ | ✅ 推奨 | 入力長制限やコスト設定に注意 |
| PBKDF2 | 反復回数を設定して計算コストを高めるKDF | ✅ 条件付きで推奨 | FIPSなどの要件がある環境で選ばれることがある。十分な反復回数が必要 |
| scrypt | メモリ使用量を増やし、GPUなどによる大量試行を困難にする | ○ 使用可 | パラメータ設定と実装の確認が必要 |
| MD5・SHA-1 | 高速な汎用ハッシュ関数 | ❌ パスワード保存には不適切 | ソルトなしの場合、レインボーテーブルや辞書攻撃のリスクが高い |
| SHA-256・SHA-512単体 | 暗号学的な用途で広く使われる高速な汎用ハッシュ関数 | ⚠️ 単体でのパスワード保存には不適切 | PBKDF2-HMAC-SHA256など、KDFとして使う場合とは区別する |
開発者向けの実装対策

Argon2idの実装例(Python)
以下は、PythonでArgon2id系のライブラリを使ってパスワードをハッシュ化・検証する例です。実際のパラメータは、サーバー性能やセキュリティ要件に応じて調整してください。
from argon2 import PasswordHasher
ph = PasswordHasher(
time_cost=3,
memory_cost=65536,
parallelism=4
)
# パスワードのハッシュ化
hashed = ph.hash("user_password")
# パスワードの検証
try:
ph.verify(hashed, "user_password")
print("認証成功")
except Exception:
print("認証失敗")
bcryptの実装例(PHP)
PHPでは、`password_hash()` と `password_verify()` を使うことで、安全なパスワードハッシュと検証を実装できます。
<?php
// パスワードのハッシュ化
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
// パスワードの検証
if (password_verify($password, $hash)) {
echo "認証成功";
}
?>
開発者が守るべきパスワードハッシュの原則
- ユーザーごと・パスワードごとに十分ランダムなソルトを使う
- MD5・SHA-1・SHA-256単体をパスワード保存に使用しない
- Argon2id・bcrypt・PBKDF2などのパスワード保存向けアルゴリズムを使う
- コストパラメータを適切に設定する
- ハードウェア性能の向上に合わせてパラメータを定期的に見直す
- 古いアルゴリズムからのマイグレーションを計画する
- 次回ログイン時に新しい方式で再ハッシュする仕組みを用意する
- パスワードの平文をログやDBに保存しない
- 多要素認証を併用し、パスワード単独に依存しない
レインボーテーブルに関連する被害・注意事例2選
事例1:LinkedInのパスワードハッシュ流出
ソルトなしのパスワードハッシュ保存の危険性を示す代表的な事例が、LinkedInのパスワード流出です。LinkedInは2012年、約650万件のパスワードが盗まれたことを公表しました。
当時のLinkedInは、パスワードをハッシュ化して保存していましたが、ソルトを組み合わせた方式ではありませんでした。そのため、攻撃者が流出したハッシュ値に対して、辞書攻撃や事前計算済みテーブルを使い、弱いパスワードを推測できる可能性がありました。
LinkedInはその後、パスワード保存方式を、ハッシュ化のみの方式から、ハッシュ化とソルトを組み合わせた方式へ移行したと説明しています。この事例は、「ハッシュ化しているから安全」とは言い切れず、ユーザーごとのソルトや専用のパスワードハッシュアルゴリズムが重要であることを示しています。
参考:LinkedIn summarizes password theft and member security efforts|LinkedIn
事例2:ハッシュ化されたパスワードが流出対象に含まれた国内事例
国内でも、情報流出時にハッシュ化されたパスワードが対象に含まれる事例があります。サイバーセキュリティ.comの記事では、ポルシェジャパンの不正アクセスに関する最終調査報告で、メールアドレスやハッシュ化されたパスワードの漏えい可能性が記載されています。
また、ダイドーグループのランサムウェア被害に関する続報では、グループが貸与しているパソコンのIDおよびハッシュ化されたパスワード、一部の生産管理・物流システムのIDやハッシュ化されたパスワードが流出対象に含まれるとされています。
ハッシュ化されたパスワードであっても、保存方式が弱い場合や、ソルト・ストレッチングが不十分な場合、攻撃者に推測されるリスクがあります。流出時には、パスワードリセット、使い回し先への注意喚起、多要素認証の有効化、保存方式の見直しを行うことが重要です。
よくある質問(FAQ)
Q. レインボーテーブル攻撃とブルートフォース攻撃はどちらが危険?
ソルトなしの高速なハッシュに対しては、レインボーテーブル攻撃が有効になる場合があります。事前計算済みのテーブルを利用できるため、テーブルに含まれる範囲のパスワード候補であれば、リアルタイム計算より効率的に探索できることがあります。
一方、ユーザーごとに十分ランダムなソルトを使っている場合、既製のレインボーテーブルは実用上使いにくくなります。その場合は、辞書攻撃やブルートフォース攻撃への耐性を高めるために、Argon2id、bcrypt、PBKDF2などの低速なパスワードハッシュを使うことが重要です。
Q. ソルトを使えばレインボーテーブル攻撃は完全に防げますか?
ユーザーごとに十分ランダムなソルトを使えば、既製のレインボーテーブルは実用上使いにくくなります。ただし、短いパスワードや使い回しパスワードは、辞書攻撃や総当たり攻撃で推測される可能性があります。
そのため、ソルトだけでなく、Argon2id、bcrypt、PBKDF2などの低速なパスワードハッシュを使い、多要素認証やパスワード使い回し対策も組み合わせることが重要です。
Q. SHA-256をパスワードのハッシュに使うのはなぜ問題なのですか?
SHA-256自体は、ファイルの改ざん検知やデジタル署名などで広く使われる暗号学的ハッシュ関数です。しかし、SHA-256は高速に計算できるように設計されているため、パスワード保存に単体で使うと、攻撃者がGPUなどで大量の候補を試しやすくなります。
パスワード保存では、意図的に計算コストを高められるArgon2id、bcrypt、PBKDF2などを使う必要があります。なお、PBKDF2-HMAC-SHA256のように、KDFの内部でSHA-256を使う場合は、SHA-256単体で保存する場合とは異なります。
Q. 既存のシステムでMD5を使っている場合、どう移行すればいいですか?
既存のMD5ハッシュをbcryptやArgon2idに直接一括変換することはできません。ハッシュは一方向の処理であり、元のパスワードを取り出せないためです。
一般的には、ユーザーが次回ログインしたタイミングで、入力された正しいパスワードを確認し、そのパスワードを新しい方式で再ハッシュして保存します。移行期間中は、パスワードリセットの促進、不審ログインの監視、多要素認証の導入、古いハッシュ方式の利用状況の可視化を行うことが重要です。
Q. パスワードマネージャーでレインボーテーブル攻撃の被害を受けない?
パスワードマネージャーを使うことで、サービスごとに長くランダムなパスワードを設定しやすくなります。これにより、辞書攻撃や総当たり攻撃に対する耐性は高まります。
ただし、サービス側がソルトなしの高速ハッシュを使っていた場合、弱いパスワードや使い回しパスワードは推測されるリスクがあります。利用者側はパスワードマネージャーと多要素認証を使い、サービス提供者側はArgon2idやbcryptなどの適切なパスワード保存方式を実装することが重要です。
まとめ
レインボーテーブルとは、ハッシュ値から元のパスワード候補を効率的に探すために、ハッシュ関数と還元関数を使ったチェーンの始点・終点を事前計算して保存しておくデータ構造です。単純な全対応表ではなく、時間・メモリのトレードオフを利用して、保存容量を抑えながら逆引きの成功率を高める仕組みです。
ソルトなしでMD5やSHA-1などの高速な汎用ハッシュ関数を使って保存された短く単純なパスワードは、辞書攻撃、総当たり攻撃、レインボーテーブル攻撃によって推測されるリスクがあります。ソルトを使うことで、既製のレインボーテーブルは実用上使いにくくなります。
ただし、ソルトだけでは十分ではありません。パスワード保存には、Argon2id、bcrypt、PBKDF2など、意図的に計算コストを高められる専用のパスワードハッシュアルゴリズムを使うことが重要です。必要に応じて、ペッパー、多要素認証、パスワードマネージャー、パスワードリセット運用も組み合わせましょう。
開発者は、MD5・SHA-1・SHA-256単体をパスワード保存に使わず、ユーザーごと・パスワードごとに十分ランダムなソルトを使い、適切なコストパラメータを設定したArgon2idやbcryptなどへ移行することが求められます。既存システムで古い方式を使っている場合は、次回ログイン時の再ハッシュなどを使って段階的に移行しましょう。
























![中小企業の情報瀬キィリティ相談窓口[30分無料]](/wp-content/uploads/2023/07/bnr_footer04.png)



レインボーテーブルは、「答えそのものを全部書いた答案集」というより、「答えにたどり着くための手順を圧縮してまとめた索引」のようなものです。ハッシュ値からパスワードを復号するわけではなく、事前計算した候補チェーンをたどることで、元のパスワード候補を見つけようとします。