パスワードはどう守られているのか

概要 — まず全体をつかむ

中級では、初級の「すりつぶし」「会員証」を、TLS・ソルト・遅いハッシュ・セッションという実名で追い直しました。上級では視点をもう一段変えて、「そもそもパスワードとは何か」——利用者とサーバが分け持つ1つの秘密(共有秘密)という正体から出発します。この見方に立つと、ハッシュもソルトもペッパーもKDFも、すべて「預かってしまった秘密を、漏れても被害が出ない形に加工する」という同じ目的の変奏に見えてきます。最後に、その努力が原理的に届かない場所(フィッシング・記憶の限界・使い回しの連鎖)と、秘密そのものを預けない道(パスワードレス)まで見ます。

(保管の土台となるハッシュの性質は ハッシュ — データの指紋、パスワードレスが依って立つ鍵の仕組みは 公開鍵暗号、トークンやセッションを含むログイン全体の設計は 認証(ログインシステム) 上級で扱います)

アニメーション『ログインの裏側』を開く
あなたサイトの受付金庫(データベース)
  • あなたパスワードを入力してログインしたい人
  • サイトの受付入力を受け取って、本人かどうかを確かめる係
  • 金庫(データベース)会員情報の保管庫。パスワードは「すりつぶした形」でしか置いていない
「▶ 再生」で通しで見るか、「次へ」で1手ずつ進めてください。
0 / 6

詳細 — 1段階ずつ追う

① 預かってしまった秘密

初級の「届ける」、中級の「経路の守りはTLS任せ」を、上級ではそもそも何を預けているのかから問い直します。

  1. パスワードは、利用者とサーバが同じ値を分け持つ「共有秘密」※1。照合できるということは、サーバ側にも必ず照合の材料が残るということ
  2. 経路の守り(TLS)は、あくまで届くまでの話。届いた先でサーバが何を保管するかは、まったく別の問題
  3. だから設計の要は「生の秘密を保管しない——照合はできるが、盗まれても元に戻せない“検証材料”だけを置く」こと
  4. この検証材料を安全にする工夫の積み重ねが、以下のハッシュ→ソルト→ペッパー→KDFという段になる

登場人物メモ(※の説明):

  • ※1 共有秘密 — 双方が同じ値を知っていることで本人確認する方式。知っている側が2つある=漏れる口も2つある、が構造的な弱点

⚠️ イレギュラー(工夫の外側にある穴):

  • 届け先が偽物なら全部無駄 — 経路が完璧でも、フィッシングでは共有秘密が自分から敵に渡る。これは強度でもハッシュでも防げない(末尾で詳述)
  • 生のまま保管していれば土台が崩れる — 上流の工夫がどれだけ精巧でも、平文保存の一点で全て無意味。まず「戻せない形で持つ」が前提
やさしく言うと(中級

🎬 アニメーション『ログインの裏側』の のところです!

入力したパスワードは、次の形でサイトへ届きます:

  1. フォームの内容は HTTPSのPOSTリクエスト※1 のボディに載る(URLには載せない——履歴やログに残るため)
  2. 通信全体が TLS※2 で暗号化されるので、パスワード自体はこの区間では生のまま
  3. つまり「経路の守りはTLS任せ、保存の守りはハッシュ任せ」という分業になっている

登場人物メモ(※の説明):

  • ※1 POSTリクエスト — 送信内容を本文(ボディ)に載せるHTTPの依頼形式。URLに載るGETと違い、記録に残りにくい
  • ※2 TLS — 通信の暗号化層。『URLを打ってから表示されるまで』の②で出てきた、あの鍵マークの正体

⚠️ イレギュラー(うまくいかないとき):

  • HTTPのままのサイト — 経路の守りがないので、パスワードが平文で流れる。ブラウザが「保護されていない通信」と警告するのはこれ
  • フィッシング — 経路も保存も完璧でも、届け先が偽物なら全て無意味。技術の外側にある最大の穴

② すりつぶす — ソルトとペッパー

「すりつぶし」の正式名は暗号学的ハッシュ関数。上級では、その前後に足す2つの塩——ソルトとペッパー——の役割を厳密に分けます。

アニメーション『雪崩効果とソルト(レインボーテーブル無効化)』を開く
雪崩効果とソルト少し変える/人ごとに変える、で指紋を作り分ける① 雪崩効果 — 入力を1文字変えると指紋は全く別物Tokyo2024ハッシュ3af9…1cTokyo2025ハッシュb7e0…44たった1文字違い→ 指紋は激変(別物)規則性が読めないので、指紋から入力を推測できない② ソルト — 同じパスワードでも人ごとに別の指紋ソルトなし(危険)Aさん:pw123Bさん:pw123ハッシュ両者とも同じ9f2a…7d同じパスワード → 同じ指紋「指紋→元」の対応表(レインボーテーブル)で一発照合されてしまう使い回し攻撃にも弱いソルトあり(安全)pw123 + 🧂ソルトAAさんHc1d4…22pw123 + 🧂ソルトBBさんH6a0f…be同じパスワードでも → 別々の指紋事前計算した対応表(レインボーテーブル)が無効になる1文字違えば指紋は激変(雪崩効果)/人ごとに違うソルトを足せば、同じパスワードでも別の指紋になる
  1. 生パスワードは保管せず、ハッシュにかけて「戻せない指紋」に変える。1文字違えば指紋が総取っ替えになる(雪崩効果)ので、似たパスワードから正解を推測する手掛かりにならない
  2. その前にソルト※1(利用者ごとのランダムな公開値)を混ぜる。狙いは強度ではなく、事前計算表(レインボーテーブル)※2 の無力化——同じパスワードでも全員のハッシュがバラけ、作り置きの表が当たらなくなる
  3. さらにペッパー※3(全利用者共通の秘密)を加える設計もある。ソルトと違いDBの外(コード外の設定・鍵管理サービス・HSM)に隔離するのが肝で、DBだけ漏れても攻撃者は総当たりに移れない
  4. 保存するのは「ソルト+ハッシュ」のセット。ペッパーは保存対象ではなく、照合のたびにアプリが持ち込む

登場人物メモ(※の説明):

  • ※1 ソルト — 利用者ごとの公開ランダム値。DBに平文で並べてよい。秘密ではない
  • ※2 レインボーテーブル — 「よくあるパスワード→ハッシュ」を計算して作り置きした逆引き表。ソルトがあると利用者ぶんの別々の表が要り、非現実的になる
  • ※3 ペッパー — 全利用者共通の秘密値。DBとは別に管理し、漏洩の“分離”を狙う。ソルトの秘密版と考えると混同しない

⚠️ イレギュラー(塩の使い方を誤ると):

  • ソルトを秘密扱いして満足する — ソルトは公開前提。秘密の効果を担うのはペッパーで、両者は役割が別物
  • ペッパーをDBに一緒に置く — ソルトと同じ場所に置いた瞬間、ペッパーの意味(分離)は消える
  • ソルト無しの高速ハッシュ(MD5等) — 過去の大規模流出の定番パターン。表で一瞬にして大半が割れる
やさしく言うと(中級

🎬 アニメーション『ログインの裏側』の のところです!

「すりつぶし」の正式名は暗号学的ハッシュ関数です。ただし、どのハッシュ関数でもいいわけではありません:

  1. 届いたパスワードに、まずソルト※1 という利用者ごとのランダムな値を混ぜる
  2. 混ぜたものをパスワード専用のハッシュ関数※2(bcrypt / scrypt / Argon2)にかける
  3. 出てきたハッシュ値とソルトをセットでDBに保存する(ソルトは隠さなくてよい)

なぜ普通のハッシュ(SHA-256など)ではだめなのか——速すぎるからです。速いハッシュはGPUで秒間数十億回試せます。パスワード用の関数は、わざと遅く設計されていて(さらに scrypt / Argon2 はメモリも大量に要求する=メモリハード※3)、総当たりの効率を殺します。

登場人物メモ(※の説明):

  • ※1 ソルト — 利用者ごとに違うランダム値。同じパスワードでも違うハッシュになるので、「よくあるパスワード→ハッシュ」の事前計算表(レインボーテーブル)が無力化する
  • ※2 bcrypt / scrypt / Argon2 — パスワード保存専用のハッシュ関数ファミリー。計算コストをパラメータで引き上げられる。このアプリも scrypt を使っている
  • ※3 メモリハード — 計算に大量のメモリを要求する性質。GPUの並列攻撃はメモリがボトルネックになり失速する(scrypt/Argon2が該当。bcryptはメモリハードではなくCPUコスト型)

⚠️ イレギュラー(ここが甘いと事故になる):

  • ソルトなしの高速ハッシュ(MD5等)で保存 — 過去の大規模流出事件の定番パターン。レインボーテーブルで一瞬で大半が割れる
  • 「パスワードを忘れた」で元のパスワードが届く — ハッシュ保存ならあり得ない挙動。平文保存の動かぬ証拠

③ わざと遅くする — パスワード専用KDF

なぜ普通のハッシュではだめなのか。上級の答えは「壊れているからではなく速すぎるから」です。

  1. 普通のハッシュ(SHA-256等)は速いのが取り柄。だがパスワード保管では、その速さが攻撃者の武器になる(GPUで秒間数十億回)
  2. そこでKDF※1(bcrypt/scrypt/Argon2/PBKDF2)を使う。わざと遅く・わざとメモリを食うように作られている
  3. ストレッチング※2 — 内部で何千〜何万回も繰り返し、1回の計算コストを意図的に底上げする。コスト係数を年々上げていける
  4. メモリハード※3 — scrypt/Argon2は大量メモリを要求。GPUやASICは演算器を並べてもメモリ帯域で頭打ちになり、並列化の旨みが消える(PBKDF2・bcryptはCPUコスト型で、メモリ耐性は弱め)
  5. 正規の照合は1回きりなので数十〜数百ミリ秒で済むが、攻撃者は何十億回払わされる。この非対称が肝

登場人物メモ(※の説明):

  • ※1 KDF — Key Derivation Function(鍵導出関数)。パスワードからハッシュや鍵を導くと同時に、計算コストを調整できる
  • ※2 ストレッチング — 計算を何度も繰り返してコストを引き伸ばす技法。速いハッシュを意図的に“遅く”仕立てる
  • ※3 メモリハード — 計算に大量メモリを必須とする性質。GPU/ASICの並列攻撃をメモリ側のボトルネックで抑える

⚠️ イレギュラー(KDFの落とし穴):

  • コスト係数を上げ忘れる — ハードは年々速くなる。数年前の設定のままだと相対的に弱くなる。再ハッシュで追随する
  • ハードの進化に賭けられる — ASIC/GPUの伸びを見込むと、CPUコスト型よりメモリハードが長持ちしやすい。新規採用はArgon2が推されがち
  • 自作の“オレオレストレッチ” — SHAを1万回自前で回す等は、実績あるKDFに劣ることが多い。標準の関数を使う

④ 照合する — 定数時間比較と列挙防止

照合そのものは「入力にソルト(+ペッパー)を付けてKDFにかけ、保存値と比べる」だけ。ですが上級では、比べ方にも攻防が潜みます。

  1. 1文字ずつ比べて違った瞬間に打ち切る実装は、一致した文字数で応答時間が変わる
  2. この差を大量に測られると、正しいバイト列を先頭から順に確定していける(タイミング攻撃※1)
  3. 対策は定数時間比較※2——差が出ても最後まで走らせ、常に同じ時間で答える
  4. 同じ理屈で、存在しないIDと存在するIDで処理時間が変わるとユーザー列挙のヒントになる。応答の文言も時間も一定に均す設計にする

登場人物メモ(※の説明):

  • ※1 タイミング攻撃 — 処理時間の差から秘密を推測する攻撃。ネットワーク越しでも統計処理で微小な差を抽出できる
  • ※2 定数時間比較 — 入力の中身に関わらず一定時間で結果を返す比較。多くの言語に専用関数がある

⚠️ イレギュラー(列挙は時間からも漏れる):

  • 存在しないユーザーを即座に弾く — 「速い失敗」自体が“このIDは無い”の合図。存在しない場合もダミーのKDF計算を回して時間を均す
  • 文言の統一だけで安心する — メッセージを揃えても、時間差が残れば列挙できる。文言と時間の両方を揃えて初めて塞がる
やさしく言うと(中級

🎬 アニメーション『ログインの裏側』の ④〜⑤ のところです!

照合そのものは「ソルトを付けてハッシュ化→保存値と比較」だけですが、実戦はここが攻防の最前線です:

  1. 攻撃側の第一手は総当たり——対策は試行回数制限(レートリミット)とアカウントロック
  2. 第二手がクレデンシャルスタッフィング※1——他所で漏れたID・パスワードのセットを機械的に試す。複雑なパスワードでも使い回していれば無力
  3. 守り側は失敗応答を「IDかパスワードが違います」に統一して、IDの存在を教えない(ユーザー列挙防止)

登場人物メモ(※の説明):

  • ※1 クレデンシャルスタッフィング — 漏えいした認証情報リストの流し込み攻撃。成功率は数%でも、リストが数億件あるので成立してしまう

⚠️ イレギュラー(攻防の細部):

  • ロックの悪用 — わざと他人のIDで失敗を繰り返し、ロックさせる嫌がらせ(DoS)もある。だからロックは時限式にするなど設計に工夫がいる
  • 応答時間の差 — 「IDが存在する場合だけ処理が遅い」といった挙動の差からIDの存在が漏れることもある

⑤ 詰まらせる — レート制限・ロックアウト・漏洩照合

ここまでは主に盗まれたハッシュを手元で割る攻撃への守り。今度は本番のログイン口へ打ち込む攻撃を、入口で詰まらせます。

  1. レート制限※1 — IP・アカウント・端末ごとに試行回数を絞る。手元での総当たりはKDFで、本番への打ち込みはここで抑える(守りの分担)
  2. アカウントロックアウト — 一定回数の失敗で一時停止。ただし時限式にしないと、他人のIDでわざと失敗させてロックする嫌がらせ(DoS)に悪用される
  3. 段階的な遅延/人間確認 — 硬直的なロックより、失敗ごとに待ち時間を伸ばす・CAPTCHAを挟むほうが、正規利用者への巻き添えが小さい
  4. 漏洩パスワード照合※2 — 設定時に「既に世界のどこかで漏れているパスワード」を弾く。照合はk-匿名性※3 で行い、パスワードもハッシュ全体も送らず、ハッシュの先頭数文字だけを問い合わせて残りは手元で突き合わせる

登場人物メモ(※の説明):

  • ※1 レート制限 — 単位時間あたりの試行数に上限を設ける防御。総当たりの“打ち込み速度”を殺す
  • ※2 漏洩パスワード照合 — 既知の流出リストに載るパスワードを設定時に拒否する仕組み(Have I Been Pwned 的なサービス)
  • ※3 k-匿名性 — 問い合わせ対象を多数の候補に紛れさせ、何を調べたかを特定させないプライバシー技法

⚠️ イレギュラー(詰まらせ方の副作用):

  • ロックの悪用(被害者ロックDoS) — 時限解除・段階遅延・アカウント単位+IP単位の併用で緩和する
  • 分散型の総当たり — 多数のIPから薄く広く来ると単純なIP制限をすり抜ける。端末指紋やアカウント単位の制限、パスキー移行が要る
  • 漏洩照合でハッシュ全体を送る — サーバ側に「誰がどの漏洩パスワードか」が溜まり新たな漏洩源になる。先頭だけ送るのが作法

⑥ 秘密を預けない道 — パスワードレス

ここまでは全部「預かってしまった共有秘密をどう守るか」の話でした。裏を返せば、預けなければ守る苦労も漏れる口も消えます。

  1. WebAuthn/パスキー※1 は公開鍵暗号※2 のチャレンジ-レスポンス。端末が秘密鍵を握り、サーバには公開鍵しか渡らない
  2. だからサーバから漏れても、公開鍵は公開してよいものなので被害が出ない。共有秘密という発想そのものが消える
  3. 署名はオリジン(サイトの出自)に紐づくので、偽サイトは正しい署名を得られない——フィッシングに構造的に強い
  4. 弱点は可用性側に寄る。端末紛失時の復旧や、端末間で鍵を同期する同期パスキー(利便性が高いが鍵が端末外に出る)とデバイスバウンド(耐タンパ性が高いが機種変更に弱い)のトレードオフが残る

登場人物メモ(※の説明):

  • ※1 WebAuthn/パスキー — 公開鍵ベースの認証標準。秘密鍵は端末の安全な領域に留まり、サーバに秘密を置かない
  • ※2 公開鍵暗号 — 公開してよい鍵と秘密の鍵の対で、秘密を配送せずに本人確認や暗号化を可能にする(公開鍵暗号 参照)

⚠️ イレギュラー(移行期の綻び):

  • 「パスキー=パスワードを暗号化して保存」ではない — そもそもサーバに秘密が無い。まったく別の発想と捉える
  • フォールバックが穴になる — パスワードやSMSの逃げ道を残すと、そこがフィッシングの標的になり、パスキーの強みが薄まる

(トークン・セッション・委任まで含むログイン設計の全体像は 認証(ログインシステム) 上級へ)

⚠️ 上級の限界 — 強度が無力な場所

最後に、ここまでの工夫が原理的に届かない場所を整理します。上級の到達点は、対策の限界を正しく引けることです。

  • フィッシングに強度は効かない — 40文字の乱数でも、偽サイトに自分で入力すれば一発で渡る。パスワードの複雑さはこの経路に無力。効くのはオリジン紐付け(パスキー)や物理鍵
  • 人間の記憶が上限 — 覚えられる強いパスワードの数には限界がある。現実解は「管理アプリに強い乱数を覚えさせ、人間は覚えない」。人間が覚える前提の強度論はどこかで破綻する
  • 使い回しの連鎖 — サーバ側がどれだけ完璧でも、利用者が使い回していれば、他所の1件の漏洩が芋づるで波及する(クレデンシャルスタッフィング)。サーバの努力では塞げない、利用者側の穴
  • KDFの経年劣化 — ハードは速くなり続ける。“今は十分”なコスト係数も数年で相対的に弱くなる。上げ続けてこそ有効
  • 2FAはフィッシングを止めない — 2つ目の要素も、その場でコードを聞き出す進化型フィッシングには抜かれる。SMSコードよりオリジン紐付けのパスキーが強いのはこのため

まとめ——上級で見えるのは、パスワード対策が2つの戦線に分かれていることです。オフライン戦線(盗まれたハッシュを手元で割る攻撃)はソルト・ペッパー・KDFで、オンライン戦線(本番へ打ち込む攻撃)はレート制限・ロックアウト・漏洩照合で守る。そして両方を頑張ってもフィッシング・記憶・使い回しという人間側の限界は残り、その根本解が「共有秘密そのものを捨てる」パスワードレスです。ニュースで「ハッシュ化済みだから安全」と聞いたら、それはオフライン戦線の一部の話にすぎない、と読めるようになれば上級卒業です。

関連する知識

理解度チェック

そのまま解けます(成績は保存されません)。無料アカウントを作ると、学習の記録と進捗の山登りが始まります。

1. パスワード保管にSHA-256のような高速ハッシュではなく、bcrypt/scrypt/Argon2といったKDFを使う狙いとして最も正確なものはどれ?

2. 「漏洩済みパスワード照合」サービスに自分のパスワードが載っていないかを、プライバシーを守ったまま問い合わせる典型的な仕組みはどれ?

3. ソルトに加えて「ペッパー」を使う設計で、ペッパーがソルトと決定的に違う点はどれ?

4. ソルトがレインボーテーブル(事前計算表)を無力化する仕組みとして最も正確なものはどれ?

5. ハッシュ値の照合を「1文字ずつ比べ、違いが出た瞬間に打ち切る」実装が危ういのはなぜ?

6. 失敗回数だけを見て「一定回数でアカウントを無期限ロックする」実装に潜む弊害はどれ?

7. パスワードからハッシュや鍵を導きつつ 計算コストを意図的に調整できる関数の総称を 英字3文字で答えてください。

8. サーバには公開鍵だけを渡し 秘密鍵を端末の安全な領域に留める WebAuthnベースのパスワードレス認証の通称を カタカナで答えてください。

パスワードはどう守られているのか | Kotowary