PR 本記事には広告(Amazonアソシエイト・もしもアフィリエイト・A8.net等)が含まれます。掲載情報の正確性には努めていますが、商品の詳細は必ずリンク先で最新情報をご確認ください。
CTF・セキュリティ学習

【パスワード再設定の罠】リセットリンクから乗っ取る手口と対策|CTF思考フレームワーク #03

パスワードリセット攻撃者目線|CTF思考フレームワーク #03
安全に生きたい編集部

📖 この記事はシリーズの一部です

「CTF思考フレームワーク」 Webフォーム編 #03 / 公開中 10記事 → シリーズ一覧を見る →

「パスワードを忘れた」リンク、何気なく使ってますよね。でもここ、実はアカウント乗っ取りの黄金ルートとして攻撃者に大人気のフィーチャーです🔑

難易度:★★☆(中級)

トークンの予測可能性、リダイレクト改ざん、HTTPホストヘッダー攻撃などが絡む🔬

パスワードリセットは「メール送信→トークン付きURLでリセット」という単純フローに見えて、攻撃面が想像以上に多いです。攻撃者の思考を追っていきましょう✨

この記事の難易度

難易度:★★☆(やさしめ) / 所要:10〜12分 / 前提:#01〜#02の内容

👀 観察フェーズ:まず何を見る?

リセット機能って“裏口”になりやすいから、観察ポイント多めだよ。

パスワード再設定機能は、ログインを正面突破できないときの“裏口”になりやすい場所。攻撃者は「リセット要求→メール受信→新パスワード設定→ログイン」の一連の流れを観察して、トークンの作り方やURLの組み立て方の中に弱点を探します。下のチェックリストは、観察フェーズで見るべき6つのポイントです👌

  • 存在しないメアドへの応答 リセット要求時、登録されていないメアドにも「そのアドレスにメールを送りました」と一律に返すか。実在判定をさせない設計になっているかの確認
  • リセットURLのトークン形式 メール本文のリセットURLに含まれるトークン(本人確認用の使い捨て文字列)が、連番/タイムスタンプ/UUID(推測困難なランダムID)/JWT(署名付きトークン)のどれか。連番やタイムスタンプは予測可能で危険
  • トークンの有効期限と再利用可否 発行から何時間使えるか、1度使ったら無効化されるか。無期限・何度でも使える実装は乗っ取りの温床に
  • リセットURLのドメインの作り方 メール本文のURLが、リクエスト時のHostヘッダ(ブラウザがアクセスしたドメイン情報)をそのまま使って組み立てられていないか。Hostヘッダ偽装でフィッシングサイトに誘導される典型的な穴です
  • 新パスワード設定時の追加確認 現在のパスワードや本人確認質問を要求するか。トークンだけで新パスを設定できる実装は、トークンが漏れた瞬間に終わります
  • リセット完了後のセッション処理 パスワードを変えたら他端末・他ブラウザのログイン状態を全部切るか。残ったままだと、攻撃者のセッションが生き続けます

受け取ったメールの生ソース表示(Gmailなら「メッセージのソースを表示」)からURLをコピーして、トークン部分をBase64デコードjwt.ioなどで貼り付けると一発)してみるのがおすすめ。中にユーザーIDや有効期限が平文で入っていれば、それだけで設計の弱点が見えてきます👀

トークンの形式って攻撃の鍵になるんだ…意識したことなかった💧

🤔 仮説フェーズ:攻撃者ならどう考える?

リセットは本人確認の代わりになる機能。だから狙われやすいんだ。

パスワード再設定機能は本人確認の代わりを果たす場所。だからこそ攻撃者は「トークンを盗む/推測する/迂回する」の3方向から狙ってきます。代表的な4つの仮説を紹介しますが、全部覚える必要はなくて「こういう見方をするんだ」と眺めてもらえればOK。守る側にとっては、この4つに当てはまらない設計=攻撃者に取り付く島がないというヒントになります。

🎯 仮説①:トークンが連番・タイムスタンプ=予測可能

トークンを連番やタイムスタンプ+ユーザーIDから生成している実装は、被害者がリセット要求した瞬間に攻撃者が「だいたいこの時刻にこのIDで作られたはず」と推測できてしまいます。UUID v4(バージョン4:完全ランダム生成のID形式)や暗号学的に安全な乱数(CSPRNG)を使うのが鉄則です。

え、時刻+IDで作るとそんなに簡単にバレるの…!?

🪤 仮説②:HostヘッダーがリセットURLに使われる

メール本文のリセットURLが、リクエストの Host ヘッダ(ブラウザがアクセスしたドメイン情報)をそのまま信頼して組み立てていると、攻撃者が Host: attacker.com に偽装したリクエストを送れば、被害者宛のメールに attacker.com 経由のリセットURLが入って届きます。被害者がクリックした瞬間にトークンが攻撃者のサーバーに渡り、即座に乗っ取り完了です。

えっ、メールに届くURLが攻撃者のドメインに書き換わるの…?怖すぎ💧

🔓 仮説③:リセット完了APIにIDORがある

パスワード変更APIに userId パラメータが露出していて、自分のトークンで他人のIDを指定してもサーバーが通してしまう実装だと、他人のパスワードを自由に書き換えられます。これをIDOR(Insecure Direct Object Reference:認可漏れによる直接オブジェクト参照)と呼びます。トークンとユーザーIDの紐付けをサーバー側で必ず検証する必要があります。

うわ、userIdを変えるだけで他人のパスワード変えられるの…?致命的すぎる💧

⏰ 仮説④:トークンに有効期限がない/再利用できる

トークンに有効期限がない、または1度使った後も再度使える実装だと、メール窃盗・SSRF(サーバ側からの内部リクエスト悪用)・ログイン履歴漏洩などで一度漏れたトークンがいつまでも有効に。15〜60分の有効期限+使い切り(1回使ったら無効化)が原則です。

昔のメールに残ってるリンクでいまだに侵入できるのか…ヤバい

これら4つを順番にチェックしていくのが、攻撃者の典型的な思考パターン。リセット機能はログイン画面と同じくらい狙われる場所なので、観察→仮説までしっかり押さえたら、次は実際にどう確かめるか——検証フェーズに進みます💡

🔬 検証フェーズ:実際に試す手順

リセットの検証はトークン形式と有効期限が中心になるよ。

仮説が立ったら検証フェーズです。検証は“答え合わせ”の時間。1つずつ小さく試して反応を確かめます。必ず自分で立てた検証環境か、許可されたCTF用サイトでやってください。本番サイトに対して試すのは法律違反になります(最後のお約束で詳しく書きます)。

STEP 1
メアド列挙の確認

自分が登録したメアドと、存在しないメアド(nobody12345@example.comなど)でリセット要求を送り、レスポンス(メッセージ・ステータスコード・応答時間)が同一かを確認します。差があれば、その時点で「実在メアドかどうか」を判定する仕組みになっています。

STEP 2
トークン形式の解析

届いたメールのリセットURLからトークン部分を3〜5回採取して並べて比較します。文字長や文字種、連続発行時の差分を見て、連番/タイムスタンプ/UUID v1(時刻ベース:先頭が時間順に近づく)なら予測可能性あり。UUID v4や32文字以上のランダム文字列なら合格点です。

STEP 3
トークン使い回しテスト

一度使ってパスワードを変えたあとのリセットURLを、もう一度ブラウザで開いて新パスワードを設定してみる。エラーにならず通ってしまえばトークン使い回し可能=大問題。1回使ったら即サーバー側で無効化するのが基本です。

STEP 4
Hostヘッダーインジェクション

curl でリセット要求を送る際、Host: attacker.com ヘッダを付けて投げてみます。届いたメールのリンクが attacker.com ドメインで組み立てられていれば、Hostヘッダインジェクション(リクエストヘッダの偽装で出力URLを書き換える攻撃)が成立する脆弱な実装です。

STEP 5
リセット後セッション確認

PCとスマホの両方で同じアカウントにログインしておき、PC側でパスワードをリセット。スマホ側のログインが自動で切れるかを確認します。切れない実装は、攻撃者がリセットで奪った後も本人の他端末のセッションが生きたままになるので、被害者が気づきにくい設計です。

うわ、トークンの長さや文字種を見ただけで生成方法が推測できちゃうの!?

そう。UUID v4で十分長く、毎回新しいもの。これが鉄則。

⚔️ 攻撃フェーズ:攻撃者ならこう攻める

“なぜ通るか”を理解するのがゴール。攻撃の流れが分かれば対策も見える。

検証で「ここ弱いな」と判断したら、いよいよ実際の攻撃に移ります。リセット機能でよくある攻撃はこの3パターン。“なぜ通るのか”を理解できれば、守る側の打ち手も見えてきます

① トークン予測攻撃

トークンがtimestamp + userIdのような予測可能な要素から作られていると、攻撃者は被害者のリセット要求を観測した瞬間に「いま発行されたであろうトークン」を計算で割り出せます。被害者がメールを開いてクリックする前の数秒〜数分の隙間に攻撃者が先にURLを叩けば、アカウントは奪取完了です💥

② Hostヘッダー攻撃

リセット要求を Host: attacker.com ヘッダ付きで送ると、メール本文のリセットURLが https://attacker.com/reset?token=... という形で被害者に届きます。被害者は普段使っているサービスからのメールだと思ってクリック——その瞬間にトークンが攻撃者のサーバーへ漏洩。攻撃者はそのトークンで本物のサービス側にアクセスして、被害者のパスワードを書き換えられます⚠️

③ IDOR with リセットAPI

リセット完了APIに userId パラメータが露出していて、サーバー側で「このトークンはこのユーザーIDのもの」という紐付けチェックを怠っていると、自分のトークンを使って userId=他人のID で送るだけで他人のパスワードを書き換えられます。完全乗っ取りに直結する致命バグです。

えっ、Hostヘッダーを書き換えるだけでメールのURLが攻撃者ドメインに…ホラーじゃん💧

結果として、こんな”フラグ”を取られちゃうイメージ:

POST /api/reset-password
{"token":"my-token","userId":42,"newPassword":"hacked"}
→ 200 OK
CTF{idor_in_password_reset}

パスワードリセットの脆弱性は、「他人のアカウント完全乗っ取り」に直結する最重要ポイント。攻撃のインパクトが極大なので、バグ報奨金プログラムでも高額査定の対象になります🚨 許可されていない実環境への攻撃は不正アクセス禁止法違反です。試すなら必ず自分の検証環境かCTF用サイトで🚫

🛡️ 防御フェーズ:どう守る?

やっとお待ちかね、守る側の打ち手。攻撃を見たあとだとスッと入ってくるよ。

攻撃側を理解できれば、守る側の打ち手も自然と見えてきます。設計/実装/運用の3レイヤーで重ねて考えるのがコツ。リセット機能は乗っ取りに直結するので、「トークンが漏れても被害が広がらない」設計を意識するのがポイントです🛡️

🏗️ 設計レベル
  • リセット応答は実在問わず統一 存在しないメアドにも「そのアドレスにメールを送りました」と返す。実在判定をさせない
  • トークンは暗号論的乱数で128bit以上 CSPRNG(暗号学的に安全な擬似乱数生成器:予測不能性が保証された乱数の作り方)で生成。UUID v4や32文字以上のランダム文字列が目安
  • URLは正規ドメインから固定生成 サーバー設定(環境変数や設定ファイル)に書いた正規ドメインを使い、Hostヘッダの値を信頼しない。Hostヘッダインジェクションへの根本対策
  • リセット完了で全セッション無効化+通知 パスワード変更時に他端末のログインを全部切り、本人に「変更されました」のメール通知を送る
⚙️ 実装レベル
  • トークンは1回限り+有効期限15〜30分 1度使ったら即無効化、未使用でも短時間で失効。漏れたときの被害ウインドウを最小化
  • IP単位のレート制限 同IPから1日5回まで、など総当たりや嫌がらせリセットを抑止
  • リセット完了APIは認証済みユーザー限定でuserIdを受け付けない トークンから一意にユーザーが特定できる設計にして、パラメータで他人のIDを指定できないようにする(IDOR対策)
  • OTP方式は試行回数と有効期限を厳しく 6桁コード方式(メールやSMSで届く一時コード)は推測攻撃に弱いので、試行5回程度/有効期限5〜10分を必須に
🔐 運用レベル
  • リセット要求の異常検知 短時間に大量のリセット要求、普段と違う国・端末からのアクセス、などをアラート化
  • リセット完了通知は別経路を併用 メール以外にプッシュ通知や認証アプリでも通知すると、本人が異変に気づきやすい。SMSは「SIMスワップ攻撃」(携帯番号を奪う手口)のリスクがあるため近年は非推奨です
  • パスワード変更履歴をユーザーに表示 いつ変更されたか・どの端末からか、をユーザー自身が確認できる動線を作る

なるほど…UUID + 短い有効期限 + 使い切りがリセットの基本セットなんだね!

その通り。トークン管理がリセット機能のキモだよ🛡️

🛡️ 今日からできる対策ツール

記事中で出てきた「強いパスワード」「使い回さない」を全部自力でやろうとすると、現実的にはすぐ限界がきます。パスワード管理ツールを1つ入れておけば、複雑なパスワードを各サイトごとに自動生成・自動入力できて、覚えるのは「マスターパスワード1つだけ」。今日から始められる現実的な防御策として、🔑「ワンパス」がおすすめです。

PR / 広告

ソースネクスト

※ 上記は他社サービスへのリンクです。購入は各自でご判断ください。

⚠️ よくある落とし穴

  1. トークンにユーザーIDをそのまま含めてしまう token=user42-abc...のような形だと、攻撃者がID部分を書き換えて他人のリセットを試せます。トークンとユーザーの紐付けはサーバー側のDBで管理するのが鉄則
  2. メール送信遅延で複数トークンが同時有効に ユーザーが「メール来ない」と2回押すと2通届き、両方が有効になっている実装が意外と多い。新しいトークン発行時に古い方を必ず無効化
  3. リセットリンクがログやRefererに残る Webサーバーのアクセスログ、Refererヘッダ(リンクの遷移元情報)、ブラウザ履歴などにトークン付きURLが平文で残ると、内部関係者やプロキシ経由で漏洩する経路に。クエリ文字列ではなくPOSTで送るなどの工夫を

🧰 ツール早見表

ツール何ができる使いどころ
Burp Suiteリセット要求のリクエストを止めて改ざん・再送できる多機能ツールHostヘッダ攻撃やIDORの検証
CyberChefトークンを貼り付けてBase64・JWT・各種エンコード解析トークン形式の分析
Hashcat弱いトークンや短い乱数を総当たりで照合検証フェーズ(演習環境のみ)
jwt.ioJWTを貼るだけでヘッダ・ペイロードをデコード表示、署名検証も可JWT形式トークンの解析
curlコマンドラインでHostヘッダなどを自由に書き換えてリクエスト送信Hostヘッダインジェクションの検証

🎓 本気で学びたい人へ

「Webセキュリティを趣味から仕事に変えたい」「インフラ寄りで体系的に学びたい」という方へ。🎓 ササエルはインフラエンジニアに特化したオンラインスクールで、セキュリティ設計の基礎から実務スキルまで段階的に学べます。

PR / 広告

ササエル

📚 もっと深く学びたい人へ

攻撃と防御の両方を1冊で学びたいなら、『ホワイトハッカー入門 第2版』が分かりやすい入口です。本記事の「観察→仮説→検証」の流れを、より幅広いテーマで体系的に追えます📚

🤝 大事なお約束

必ず守ってね

この記事で紹介した手法は、必ず自分の検証環境か、許可されたCTF・脆弱性報奨金プログラム(HackerOne、Bugcrowd など、企業が公式に「攻撃して脆弱性を報告してOK」と募集しているサービス)でだけ試してください。他人のサービスに無断で攻撃を仕掛けるのは不正アクセス禁止法違反、立派な犯罪です。学んだ知識は、ぜひ「守る側」に活かしましょう🤝

📚 次に読みたい

📚 シリーズ全体の一覧を見る →

CTF・セキュリティ学習ハブページへ

記事URLをコピーしました