セキュリティ対策
パスワードリセットの設計欠陥 — 認証を固めても、ここが弱いと全部通る
パスワードを長くしても多要素認証を入れても、『パスワードを忘れた方はこちら』が弱ければ、攻撃者はそこから正面ではなく横から入れます。リセット機能で実際に壊れる5つの型と、OWASPが要求している設計要件、そして仕様が数字を決めていない部分をどう自分で決めるかを、防御目線で解説します(CWE-640)。
「パスワードを忘れた方はこちら」——このリンクの先は、パスワードを知らない人にパスワードを作らせるための仕組みです。つまりそれ自体がひとつの認証経路であり、たいていの場合、そのサービスでいちばん弱い認証経路になっています。
なぜ「認証を固めた」が効かないのか
正面:ログイン
長いパスワード + 多要素認証 + レート制限 + 総当たり検知
─────── 同じアカウントへ ───────
横:パスワードリセット
メールが届けば通る/第2要素を要求しない実装が多い/トークンの強度は目に見えない
リセット機能は「利用者を助ける便利機能」として作られるため、認証機能と同じ厳しさで設計・レビューされないことがあります。しかし機能としては、パスワードを知らない相手にアカウントの支配権を渡す処理です。認証本体と同格に扱う必要があります。
この観点は、当サイトが 2026年の国内インシデントを侵入経路で分類した記事 で示した傾向とも重なります。脆弱性を壊して入る型より、鍵を持って入る型のほうが多い。リセット機能は、その「鍵」を正規の手続きで発行してしまう場所です。
実際に壊れる5つの型
- ① 推測できるトークン
- 連番、時刻由来、短い文字列、非暗号用の乱数(
Math.random()相当)で作られたトークン。総当たりや推測で他人のリセットを完了できてしまう - ② 失効しないトークン
- 有効期限がない/使用後も生き続ける/何度でも使える。過去に一度発行されたリンクが、いつまでも合鍵として機能する
- ③ メールに残り続けるリンク
- メールボックスが読まれた時点で鍵も読まれる。転送設定・共有アカウント・退職者の受信箱など、メールは想像より多くの目に触れる
- ④ リンクの宛先を外から差し替えられる
- リセットURLをリクエストの
Hostヘッダから組み立てていると、外部から与えられた値がそのままメール本文のリンクになり得る(Hostヘッダインジェクション) - ⑤ 応答の差でアカウントの存在が分かる
- 「登録されていません」という親切な表示や、応答時間の差が、会員かどうかを外から確かめる照会窓口になる(ユーザー列挙)
CWE-640「Weak Password Recovery Mechanism for Forgotten Password」は、この類型に付けられた名前です。原文の定義は「元のパスワードを知らなくても利用者がパスワードを復旧・変更できる仕組みを備えているが、その仕組みが弱い」。つまり機能があること自体が問題なのではなく、その強度が本体の認証に釣り合っていないことが問題だという整理です。
秘密の質問を“唯一の手段”にしない
OWASPは、いわゆる秘密の質問について「答えがしばしば容易に推測できる・入手できるため、パスワードのリセット手段として単独で使うべきではない」としています。ただし他の方法と組み合わせる追加の層としてなら有効とも書かれています。母親の旧姓や出身校は、SNSと名簿の時代には秘密ではありません。
仕様が要求していること/自分で決めること
ここが実装で最も迷う部分です。OWASPが明示している要件と、明示していない(=実装者が決める)部分を分けて扱ってください。
OWASPが明示している要件
・トークンは暗号学的に安全な乱数生成器で生成する
・総当たりに耐える十分な長さにする
・使用後に無効化する
・存在する/しないアカウントで一貫したメッセージを返す
・応答時間も一貫させる(列挙の防止)
・レート制限・CAPTCHA等で自動化された大量送信を抑える
・既存セッションを自動で失効させるか、利用者に失効するか尋ねる
・リセットした旨の通知メールを送る(パスワードは書かない)
・リセットURLの生成にHost ヘッダを信用しない——ハードコードするか、信頼するドメインの一覧と照合する
・URLはHTTPSにする
仕様が数字を決めていない部分(=あなたが決める)
・トークンの具体的な長さ——「十分な長さ」としか書かれていない
・有効期限の分数——「使用後に無効化」は要求されているが、時間による失効の数値はない
数字が書かれていないことを「決めなくていい」と読まないこと。ここは実装者が根拠を持って決め、記録しておく部分です。
当サイトの実務上の目安:URLセーフな形で128ビット相当以上の乱数/有効期限は数十分程度/使用と同時に失効/同一アカウントで再発行したら古いものも失効。数字そのものより「推測できない・使い回せない・いつまでも生きていない」の3条件を満たすことが目的です。
実装するときの順番
トークンを推測不能にする(最優先)
暗号用の乱数生成器で生成し、URLセーフな形式に符号化する。非暗号用の乱数を使わない——「ランダムに見える」ことと「予測できない」ことは別です。データベースにはトークンそのものではなくハッシュを保存すれば、DBが読まれた場合にも即座に鍵にはなりません(保存の考え方は パスワードの保存とハッシュ・ソルト と同じ発想です)。
寿命を与え、一度で使い切らせる
使用と同時に無効化し、時間でも失効させる。同じアカウントで新しく発行したら、古いトークンも同時に失効させること。ここを忘れると、②の「失効しないトークン」に戻ります。
URLを外部入力から組み立てない
リセットリンクは設定値から生成するか、信頼するドメインの一覧と照合する。リクエストヘッダの値をそのまま使わない。これはOWASPが名指しで挙げている項目です。
応答を一定にし、レート制限を掛ける
「送信しました」という同じ文言・同じ所要時間を返し、実際に登録がある場合だけメールを送る。加えて、アカウント単位のレート制限やCAPTCHAで自動化された連続要求を抑える。利用者は困らず、外からは区別がつかない状態が目標です。
完了時に「後始末」まで行う
リセット完了と同時に既存セッションを失効させ(乗っ取られていた場合、これが縁を切る唯一の手段です)、リセットされた旨の通知メールを送る(パスワードは書かない)。可能なら、リセット経路にも第2要素の確認を要求し、リセットが多要素認証の迂回路にならないようにします。
リセットの本当の依存先は、メールボックスです
ここまでの対策をすべて実施しても、リセットの安全性は最終的に「メールを受け取れるのは本人だけか」に依存します。メールアカウントが乗っ取られていれば、正しく設計されたリセット機能ほど確実に鍵を渡してしまいます。だから利用者側の最優先も同じ結論になります——メールアカウントにこそ、最も強い保護(強い固有のパスワードと多要素認証、できればパスキー)を掛ける。事業者側の事故で被害が広がる経路も、たいていここを通ります(レンタルサーバーが不正アクセスされたとき、利用者は何をすべきか)。
利用者側の見分け方・気づき方
- 心当たりのないリセットメールが届いた = 誰かがあなたのメールアドレスでリセットを試した通知です。リンクは踏まず、サービスに自分でログインして確認する(フィッシングのメールも同じ見た目で届きます)。
- リセット後に「他の端末からログアウトされた」 = 正しい実装のサインです。逆に、リセットしても他端末のセッションが生き続けるサービスは、乗っ取られたときに縁を切れません。
- リセット手続きだけで第2要素を聞かれない = そのサービスでは多要素認証がリセット経路で迂回できる可能性があります。重要なアカウントほど、この挙動を一度確かめておく価値があります。
- パスワードの使い回しをやめる作業は パスワードマネージャー に任せるのが現実解です。
当サイトの視点:便利機能ではなく、認証機能として設計する
リセットが弱くなる原因は技術的な難しさではなく、位置づけの誤りです。「ログイン」は認証チームが厳しく作るのに、「パスワードを忘れた方はこちら」はサポート導線として軽く作られる——この非対称が穴になります。当サイトの立場は単純で、アカウントの支配権を渡す処理はすべて認証機能。リセット、メールアドレス変更、第2要素の再登録、サポートによる手動復旧——強度は「一番厚いところ」ではなく「一番薄いところ」で決まります。自分のサービスで、アカウントに到達できる経路を書き出してみてください。たいてい、想定より多くあります。
出典(一次情報)
- OWASP Cheat Sheet Series「Forgot Password Cheat Sheet」 — cheatsheetseries.owasp.org(本記事の「明示されている要件」はすべてこの文書の記述にもとづきます。トークンの具体的な桁数・有効期限の分数は同文書に記載がありません)
- MITRE CWE-640「Weak Password Recovery Mechanism for Forgotten Password」 — cwe.mitre.org
次に読む
- 対策:パスワードマネージャーの選び方と使い方 / パスワードの保存とハッシュ・ソルト
- 用語:2要素認証とは / パスキーとは / フィッシングとは
- 傾向:2026年の侵入経路は「認証情報」型が主流
よくある質問
Q多要素認証を入れていれば、パスワードリセットが弱くても大丈夫ですか?
いいえ。リセット経路で多要素認証を要求していない実装は多く、その場合リセットは『第2要素を迂回してアカウントを取り直す道』になります。守るべきは『ログイン画面の強さ』ではなく『アカウントに到達できる経路すべての強さ』です。リセット完了時に既存セッションを失効させ、可能なら第2要素の確認をリセット経路にも要求してください。
Qリセットのトークンはどれくらいの長さ・有効期限にすべきですか?
OWASPのForgot Passwordチートシートは『暗号学的に安全な乱数生成器で生成する』『総当たりに耐える十分な長さ』『使用後に無効化する』とだけ定めており、具体的な桁数や分数は示していません。つまりこの数字は実装者が決める部分です。当サイトの実務上の目安は、URLセーフな形で128ビット相当以上の乱数、有効期限は用途に応じて短く(数十分程度)、使用と同時に失効、同一アカウントで新しく発行したら古いものも失効、です。数字そのものより『推測できない・使い回せない・いつまでも生きていない』の3つを満たすことが目的です。
Q『そのメールアドレスは登録されていません』と表示するのは親切では?
利用者には親切ですが、攻撃者にとっては『どのメールアドレスがこのサービスの会員か』を確かめる無料の照会窓口になります。OWASPは、存在するアカウントと存在しないアカウントで一貫したメッセージを返すこと、さらに応答時間も一貫させることを求めています。表示を揃えたうえで、実際に登録がある場合だけメールを送る——これで利用者は困らず、外からは区別がつきません。
Q利用者側で気をつけられることはありますか?
自分宛に心当たりのないリセットメールが届いたら、それは『誰かがあなたのメールアドレスでリセットを試した』という通知です。リンクは踏まず、サービスに自分でログインして、パスワードの使い回しがないか・多要素認証が有効かを確認してください。そしてリセットの要はメールボックスそのものです。メールが読まれる状態だと、多くのサービスの鍵が芋づるで開きます。メールアカウントには最も強い保護を掛けてください。