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

概要 — まず全体をつかむ

初級では「すりつぶし」「会員証」というたとえで流れを追いました。ここでは同じ旅を実際の技術の名前で追い直します。読み終わる頃には、「〇〇社から流出、パスワードはハッシュ化済み」というニュースを自分で評価できるようになっているはずです。

用語には「※1・※2…」と番号を付けて、各セクション末尾の「登場人物メモ」で説明します。

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

詳細 — 1段階ずつ追う

① 届ける

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ログインボタンを押すと、IDとパスワードはインターネットを旅してサイトの受付へ向かいます。ここで大事なのは、鍵付きの道(アドレスバーの鍵マーク、httpsって言います)を通ることです。

  1. あなたがログインボタンを押す
  2. パスワードは暗号化された通信路に乗って受付へ向かう
  3. 途中の機械(Wi-Fi・ルーター・通信網)は通過するだけ。盗み見されても中身は読めない

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

  • 鍵マークのないサイト — 道が暗号化されていないので、途中でパスワードを盗み見される可能性がある。ログインしてはいけない
  • 偽物のサイト(フィッシング) — 道がいくら安全でも、届け先が泥棒なら意味がない。本物そっくりの偽サイトに自分から入力してしまう被害が、実はいちばん多い

② すりつぶす

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

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

  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等)で保存 — 過去の大規模流出事件の定番パターン。レインボーテーブルで一瞬で大半が割れる
  • 「パスワードを忘れた」で元のパスワードが届く — ハッシュ保存ならあり得ない挙動。平文保存の動かぬ証拠
この部分をもっと深く(上級

「すりつぶし」の正式名は暗号学的ハッシュ関数。上級では、その前後に足す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. パスワード「sakura2024」を専用のミキサーにかける
  2. 出てくるのは「a91bc0...」のようなぐちゃぐちゃの文字列
  3. このミキサーは一方通行で、結果から元のパスワードには戻せない
  4. ただし同じパスワードを入れれば、必ず同じ結果が出てくる

「戻せないのに、同じ入力なら同じ結果」——この不思議な性質のおかげで、生のパスワードをどこにも置かずに本人確認ができます。

⚠️ イレギュラー(ここが甘いサイトだと):

  • 生のまま保存しているサイト — 金庫が破られた瞬間、全員のパスワードがそのまま流出する。「流出したけど被害が出ない」と「即・全滅」の分かれ目はここ
  • 「パスワードを忘れた」で元のパスワードがメールで届くサイト — 戻せない形で保存していれば、元のパスワードを送ることは不可能なはず。届いたら、そのサイトは生のまま保存している危険信号

③ 照合する

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

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

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

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

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

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

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

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

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

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

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

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

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

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

受付は、すりつぶした結果を金庫のものと見比べます。

  1. 受付「この、すりつぶした結果、登録ある?」
  2. 金庫が登録済みの結果と見比べる(生のパスワード同士を比べているのではない)
  3. 一致すれば本人。不一致なら「IDかパスワードが違います

失敗したときに「どちらが違うか」を教えてくれないのは、不親切なのではなくわざとです。「このIDは存在します」と教えるだけで、攻撃者はそのIDを狙い撃ちできるようになるからです。

⚠️ イレギュラー(攻撃されるとき):

  • 総当たり — 機械で何万回も試される。だから多くのサイトは「5回失敗したらしばらくロック」する
  • パスワードリスト攻撃 — 別のサイトから漏れたID・パスワードの一覧を、片っ端から試される。使い回しているパスワードだけが破られる。これが「使い回しが一番危険」と言われる理由

④ 会員証をもらう

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

「しばらく有効な会員証」の正式名はセッション※1 です:

  1. サーバはランダムで推測不能なセッションIDを発行し、DB側に「誰のものか」を記録する
  2. ブラウザにはCookie※2 として渡す。以降のリクエストに自動で添付される
  3. Cookieには HttpOnly / Secure※3 という守りの属性を付ける
  4. ログアウトや「全端末からサインアウト」は、DB側のセッションを消すことで即時に効く

さらに上の守りが2要素認証(2FA)※4——パスワード(知識)に加えて、スマホ(所持)などの2つ目を要求します。パスワードが漏れた後の最後の砦です。

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

  • ※1 セッション — ログイン状態の実体。IDの当てずっぽうが効かないよう、十分長いランダム値にする
  • ※2 Cookie — ブラウザがサイトごとに保管し、自動で送り返す小さなメモ。会員証の入れ物
  • ※3 HttpOnly / Secure — 「ページ内のプログラム(JS)から読めない」「暗号化経路でしか送らない」の2属性。会員証の盗難対策
  • ※4 2要素認証(2FA) — 知識(パスワード)+ 所持(スマホ・鍵)など、性質の違う証明を重ねる方式

⚠️ イレギュラー(会員証が狙われるとき):

  • セッションハイジャック — 会員証そのものを盗めばパスワード不要でなりすませる。HttpOnly・Secure・短い有効期限はこのための守り
  • 公共PCでのログアウト忘れ — 会員証を置きっぱなしにするのと同じ。「全端末からサインアウト」機能はこの回収に使う
このアプリ(Kotowary)は実際どうしているか

本ユニットの内容は、このアプリ自身の実装方針でもあります: パスワードは scrypt でハッシュ化して保存 / セッションはDB管理(即時失効可能) / Cookie は HttpOnly + Secure + SameSite / ログイン失敗の応答は統一 / 認証系エンドポイントにレート制限。学んだ仕組みの実物の上で、いまあなたはログインしています。

まとめ——守りは4層です: 経路(TLS)/ 保存(ソルト+遅いハッシュ)/ 照合(回数制限と列挙防止)/ 会員証(セッション属性と2FA)。流出ニュースを見たら「どの層が破られたのか」を考える。それがこのユニットの読み方です。

やさしく言うと(初級

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

照合に成功すると、受付は「しばらく有効な会員証」をくれます(セッションって言います)。

  1. 会員証はブラウザが預かって、以降のページでは会員証を見せるだけで通れる
  2. だからページを移動するたびにパスワードを打ち直さなくていい
  3. 会員証には期限があり、ログアウトすると無効になる
パスワードの作り方 — 結局どうすればいい?

順番に効き目が大きいのは、この3つです:

  1. 使い回さない — これが最重要。1サイト1パスワード。人間には覚えきれないので、パスワード管理アプリ(ブラウザ内蔵のものでOK)に覚えてもらう
  2. 長くする — 8文字より12文字、12文字より16文字。複雑な記号より長さが効く
  3. 2段階にする(2要素認証って言います) — パスワードが漏れても、スマホの確認がないと入れないようにする

逆に、効き目が薄いのに疲れるのが「定期的な変更の強制」。最近は「漏れていないなら変えなくていい、そのかわり使い回すな」が主流の考え方です。

ここまでがログインの1〜2秒の裏側です。仕組み側は「生のパスワードをどこにも置かない」ことであなたを守り、あなた側は「使い回さない」ことで自分を守る——守りは両側で1セットです。

関連する知識

理解度チェック

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

1. ハッシュ化の前に付け足す「ソルト」の目的として最も適切なものはどれ?

2. 「不正アクセスがありましたが、パスワードはハッシュ化して保存していました」という発表の正しい読み方はどれ?

3. パスワードが経路の途中で盗み見されないよう 通信全体を暗号化する層を 英字3文字で答えてください。

4. パスワード保存に SHA-256 単体ではなく bcrypt / Argon2 が推奨される理由はどれ?

5. クレデンシャルスタッフィング(パスワードリスト攻撃)への、利用者側の最も有効な対策はどれ?

6. 2要素認証(2FA)が防いでくれるのは、次のうちどれ?

7. セッションを入れるCookieに付ける「HttpOnly」と「Secure」の説明として正しいのはどれ?

8. ログイン状態の実体で 推測不能な長いランダム値をCookieで渡してページ移動のたびに提示する仕組みを カタカナで何と呼ぶ?