Shikata Ga Nai

Private? There is no such things.

パスワードリセットの裏をかく!パスワードリセットポイズニング攻撃とは?

Hello there, ('ω')ノ

🧠 パスワードリセットの基本的な仕組み

多くのウェブサイトでは、ユーザーがパスワードを忘れたときのために「パスワードリセット」機能を提供しています。その仕組みは以下のような流れです:

  1. ユーザーが自分のメールアドレスやユーザー名を入力してリセットをリクエスト。
  2. サーバーは、対応するアカウントを確認して、一意な「リセットトークン」を生成。
  3. そのトークンを含んだリセットリンクをメールで送信:
   https://normal-website.com/reset?token=abcdef123456
  1. ユーザーがリンクをクリックすると、トークンを検証し、新しいパスワードの入力画面へ。
  2. リセット完了後、トークンは無効化。

この仕組み自体はシンプルかつ比較的安全です。ただし、リンクの生成に「Hostヘッダー」が使われていると話は別です。


🧨 パスワードリセットポイズニング攻撃とは?

「Hostヘッダー」によってリセットリンクのURLが生成されている場合、攻撃者は以下のような手順で攻撃できます:

🕵️‍♂️ 攻撃手順

  1. 攻撃者が被害者のメールアドレスを使って、パスワードリセットをリクエスト。
  2. リクエストをBurpなどでキャプチャしてHostヘッダーを書き換え、自分の管理するドメイン(例:evil-user.net)に変更。
  3. サーバーはリセットリンクを被害者に送信するが、リンクのドメインは以下のようになっている:
   https://evil-user.net/reset?token=abcdef123456
  1. 被害者がリンクをクリックすると、トークンが攻撃者のサーバーに送られてしまう
  2. 攻撃者はトークンを使って本物のサイトでパスワードを変更し、アカウントを乗っ取る。

🛡️ 防御策

防御策 内容
Hostヘッダーを使わない 絶対URLが必要な場合でも、設定ファイルでドメインを指定するべき。
Hostヘッダーを検証 ホワイトリスト方式でドメインをチェック。例:DjangoならALLOWED_HOSTS
HTMLエスケープを忘れない メール本文にURLを含む場合は、Hostヘッダー由来の値をHTMLエスケープする。

✅ まとめ

ポイント 解説
パスワードリセットはトークンに依存 トークンが盗まれると誰でもパスワードを変えられる
Hostヘッダーが脆弱だとリンクを乗っ取れる 攻撃者が悪意のあるドメインでリンクを送れる
防御には構成ファイルの見直しが有効 フレームワークの設定で許可ドメインを制限するのが重要

Best regards, (^^ゞ