プロンプトとコンテキスト
サインイン済みのユーザーが新しいメールアドレスを送信します。サービスは、盗まれたセッション、メールアドレスの列挙、繰り返しのクリック、並行リクエストによるアカウント乗っ取りリスクを低減しながら、新しいアドレスの管理権を証明する必要があります。データモデル、トークンのライフサイクル、通知、セッションポリシー、レート制限、監査イベント、リカバリパスについて説明してください。
メールアドレスの変更はログイン、パスワードリカバリ、セキュリティ通知に影響するため、アカウントに対する高リスクな操作であると想定します。現在のセッションが盗まれている可能性があり、どちらかのアドレスが一時的に利用できない場合もあり、1つのアカウントに対して有効な変更リクエストは1件のみとします。
面接官がテストするポイント
面接官は、アクティブなセッションと、最近再証明されたアイデンティティとの違いを明確に理解しているかを確認したいと考えています。優れた回答では、高リスクアカウントに対して再認証または既存の多要素認証(MFA)を要求します。また、所有証明が成功するまで、変更候補のアドレスを分離して保持します。
さらに、使い捨てのランダムトークン、短い有効期間、サーバー側のトークンダイジェスト、リプレイ防止、古いアドレスへの通知、一様なエラー応答、監査イベントについても評価されます。卓越した回答では、セッションの無効化、リカバリ、並行更新に対する不変条件まで網羅します。
30秒の回答
「私は最近の再認証を必須とし、より高リスクなアカウントには既存のMFAを要求します。提案されたアドレスは、現在のアドレスを直接置き換えるのではなく、個別の保留中レコードに保存します。暗号学的に安全なランダムな使い捨てトークンを新しいアドレスに送信し、データベースにはそのダイジェスト、目的、有効期限、消費状態のみを保持します。確認トランザクションでアカウントをロックし、ダイジェスト、有効期限、バージョンを確認した上で、アトミックにアドレスを変更してリクエストを消費済みにします。古いアドレスにはセキュリティ通知とキャンセルの選択肢が送信されます。セッションはリスクに応じて無効化またはステップアップ認証されます。レスポンスは列挙攻撃に対して安全であり、リクエストはレート制限され、監査イベントにトークンが含まれることは決してありません。」
ステップごとの詳細解説
ステップ 1: アカウントと保留中リクエストのモデリング
アカウントには current_email を保持し、アカウントID、正規化された変更候補のアドレス、トークンダイジェスト、目的、有効期限、状態、バージョン、作成日時、およびリクエストを開始したセッションのリスクコンテキストを含む個別の pending_email_change レコードを保存します。証明が成功するまで、提案された値がログインやリカバリに影響を与えてはなりません。
ステップ 2: 再認証とリスク境界の設定
アクティブなログインは、そのセッションが受け入れられていることを証明するに過ぎません。最近のパスワード確認または既存のMFA要素を要求し、デバイス、IP、異常シグナルを考慮します。新しいアドレスを知っていることは、現在のアイデンティティの証明にはなりません。ステップアップの結果は短命かつ単一目的であるべきであり、恒久的な汎用クレデンシャルにしてはなりません。
ステップ 3: ワンタイムトークンの生成と配信
暗号学的に安全な乱数生成器、短いTTL、単一の目的を使用します。データベースには一方向のダイジェストのみを保存し、メールリンクに生のトークンを含めます。メッセージはアカウントが存在するかどうかを明らかにしてはなりません。再送信はレート制限され、古いトークンを無効化します。消費済み、期限切れ、または無効化されたトークンは再利用できません。
ステップ 4: アトミックな検証とコミット
確認時には、フォーマットとレートのチェックを実行し、1つのトランザクション内でアカウントと保留中の行をロックします。定数時間でダイジェストを比較し、状態、TTL、目的、バージョンを確認します。同じトランザクション内で新しいアドレスの一意性を強制し、現在のアドレスをアトミックに更新し、リクエストを消費済みにし、監査イベントを追加します。重複したクリックに対しては、副作用を繰り返すことなく、冪等または安全に処理済みの結果を返します。
ステップ 5: 古いアドレス、セッション、通知の処理
古いアドレスにセキュリティ通知を送信し、リクエストがまだ保留中である間はキャンセルできるようにします。成功時には、有効期間の長いリフレッシュトークンを無効化するか、他のセッションに再認証を要求します。高リスクアカウントでは、即座のグローバル無効化が必要になる場合があります。新しいアドレスが即座に唯一のリカバリ手段になってはなりません。
ステップ 6: 列挙、不正利用、競合状態の制御
リクエストエンドポイントと確認エンドポイントの両方で一様な処理時間とメッセージを使用し、攻撃者がアドレスが登録されているかどうかを特定できないようにします。アカウント、対象アドレス、デバイス、ネットワーク単位でレート制限をかけます。一意性制約に行ロックまたは条件付きバージョン更新を組み合わせることで、2つのリクエストが同時に成功するのを防ぎます。使用状況チェックと書き込みは同一のトランザクション境界を共有します。
ステップ 7: リカバリと利用不可時のケースの設計
配信遅延に備えて古いトークンを無効化しつつ、制限付きの再送信を許可します。古いアドレスが失われた場合、未検証の新しいアドレスを乗っ取り防止の十分な証明として受け入れてはならず、アカウントのより強力なリカバリプロセスを使用します。配信の失敗、アドレスの重複、ポリシーによる拒否では、安全なメッセージを表示しつつ、監査レコードには内部の理由コードを保持します。
ステップ 8: 脅威のテストと結果の測定
盗まれたセッション、トークンのリプレイと期限切れ、並行確認、古いアドレスからのキャンセル、リフレッシュトークンの無効化、クロスアカウントのアドレス所有、エンドポイントの列挙をテストします。ステップアップの失敗、リプレイの試行、確認から無効化までのレイテンシ、通知の到達率、手動リカバリの発生件数を測定します。データベース漏洩テストを実施し、保存されたダイジェストがトークンとして使用できないことを確認する必要があります。
トレードオフ、境界、情報利得
短いTTLはリスク露出を減らしますが、メールが遅延した際の再送信プレッシャーを高めます。回数制限付きの再送信と明示的なステータス管理で両者のバランスを取ります。すべてのセッションを無効化することはより安全ですが、複数のデバイスでの利用を中断させるため、リスク層に応じてスコープを選択できます。古いアドレスのキャンセル期間を設けることでリカバリ性が向上しますが、完了した高リスクな変更を取り消すことはできません。
ダイジェストのみの保存はデータベースの流出から保護しますが、生のトークンはリンク、ブラウザ履歴、ログ、トレーシング、アナリティクスを通じて漏洩する可能性があります。これらのパスをフィルタリングし、トークン消費後はクリーンなURLにリダイレクトします。一意性制約はアイデンティティの所有権を単純化しますが、1つのアドレスが複数のアカウントに所属できるかどうかはプロダクト側で定義する必要があります。
質の高い模範回答
「私はメールアドレスの変更を高リスクなステートマシンとして扱います。ユーザーは最近の再認証を完了し、必要に応じて既存のMFAチェックをパスします。提案されたアドレスは保留中のレコードに入り、現在のアドレスがログインとリカバリの信頼できる情報源として維持されます。CSPRNGが短いTTLを持つ使い捨てトークンを生成し、データベースにはそのダイジェスト、目的、バージョン、状態のみが保存されます。
確認トランザクションはアカウントとリクエストをロックし、ダイジェスト、有効期限、バージョン、一意性制約をチェックした後、アトミックにアドレスを更新し、リクエストを消費済みにし、監査イベントを記録します。古いアドレスはセキュリティ通知を受け取り、まだ保留中のリクエストをキャンセルできます。成功後、リフレッシュトークンは無効化され、他のセッションはリスクに応じて再度ステップアップ認証を求められます。
すべてのエンドポイントは一様なエラーと、アカウント、ターゲット、ネットワークごとのレート制限を使用します。ログにはトークンではなく理由コードが含まれます。リプレイ、競合、古いメールボックスの喪失、配信失敗のそれぞれに定義されたリカバリパスが存在し、テストではトークンの有効期限、無効化レイテンシ、列挙耐性を測定します。」
よくある間違い
- フォーム送信時にアドレスを置き換えてしまう。 証明されていないアドレスによってユーザーが締め出されたり、盗まれたセッションに乗っ取られたりする可能性があります。
- 既存のセッションのみを信用する。 セッションを盗んだ攻撃者が高リスクな操作を完了できてしまいます。
- データベースやログに生のトークンを保存する。 それらのシステムがアカウント乗っ取りの経路になります。
- トークンの再利用を許可する。 リプレイによって通知が繰り返されたり、アドレスが上書きされたりする可能性があります。
- アドレスの存在を明らかにしてしまう。 確認やリクエストのレスポンスが、アカウント列挙のオラクルになってしまいます。
- 一意性の競合状態を無視する。 2つのアカウントまたはリクエストが同一のアドレスを要求してしまう可能性があります。
- 成功後もすべての長期間セッションを維持する。 盗まれたリフレッシュトークンが有効なままになります。
- 古いアドレスが失われた際に新しいアドレスを信用する。 これにより、アカウントのリカバリ保証がバイパスされてしまいます。
フォローアップの質問と回答
なぜ最初に新しいアドレスを書き込んで非同期に検証しないのですか?
ログイン、リカバリ、通知が即座にそれを使用してしまう可能性があり、ロールバックによって競合状態が発生するためです。個別の保留値を保持することで、未検証の入力をアイデンティティ境界の外側に保つことができます。
トークンの有効期間はどのくらいにすべきですか?
リスクに依存しない決まった数値はありません。配信にかかる時間の分布と脅威目標から短い期間を選択し、回数制限付きの再送信を追加して、発行から期限切れまでの実際の挙動を測定します。
古いアドレスへの通知はMFAの代わりになりますか?
いいえ。通知とキャンセルは多層防御とリカバリのシグナルであり、高水準なアイデンティティの証明ではありません。高リスクアカウントには依然として既存のMFAメソッドまたはより強力なリカバリが必要です。
2つのタブが同時に確認を行った場合はどうなりますか?
バージョン、ワンタイム状態、トランザクションロックを使用して、1つのリクエストのみが保留中から消費済みに遷移するようにします。2番目のリクエストは冪等な結果を返し、重複した副作用は発生させません。
トークンがアナリティクスに入り込むのを防ぐにはどうすればよいですか?
ワンタイムパスを使用し、エッジおよびアプリケーション層でクエリパラメータをフィルタリングし、消費後はクリーンなURLにリダイレクトし、機密性の高いレスポンスのキャッシュを無効にします。