この記事では、ログイン画面やユーザー登録画面で無意識に情報を漏らしてしまう、危険な エラーメッセージ の実装について解説します。
セキュリティ対策は難しそうに感じるかもしれませんが、まずは基本中の基本である エラーメッセージ から見直してみましょう。
実装は簡単ですが、意外と見落とされがちなポイントです。
よくある問題のある エラーメッセージ
以下のような エラーメッセージ 、見たことありませんか?
NG例1: ユーザー登録画面
このメールアドレスはすでに登録されています
NG例2: ログイン画面
パスワードが間違っています
NG例3: パスワードリセット画面
このメールアドレスは登録されていません
一見親切な エラーメッセージ に見えますが、これらは全てセキュリティ上の問題を抱えています。
なぜこれが問題なのか
これらの エラーメッセージ は、システムに登録されているユーザー(メールアドレス)を特定できてしまうという致命的な問題があります。
情報の非対称性が生まれる
- 「このメールアドレスはすでに登録されています」→ このメールアドレスは会員である
- 「パスワードが間違っています」→ メールアドレスは正しい=会員である
- 「このメールアドレスは登録されていません」→ このメールアドレスは会員ではない
つまり、攻撃者は適当なメールアドレスをフォームに入力するだけで、誰がこのサービスの会員なのかを簡単に調べることができてしまいます。
攻撃者の視点で考える
ユーザー列挙攻撃 (User Enumeration)
攻撃者は以下のような手順で、会員情報を収集できます。
- よくあるメールアドレスのリストを用意する
- 登録フォームやログイン画面に順番に入力していく
- エラーメッセージの違いから、登録済みユーザーを特定する
- 特定したユーザーに対して、標的型攻撃を仕掛ける
実際の被害
| 攻撃手法 | 悪用方法 |
|---|---|
| フィッシング詐欺の精度向上 | 「あなたは○○サービスの会員ですよね?」と確実に言える |
| パスワードリスト攻撃の効率化 | 他サイトで流出したメールアドレスが、このサイトでも使われているか確認できる |
| ソーシャルエンジニアリング | 「このサービスを使っている」という情報自体が悪用される |
正しい エラーメッセージ の実装
OK例: ユーザー登録画面
メールアドレスまたはパスワードに問題があります
OK例: ログイン画面
メールアドレスまたはパスワードが正しくありません
どちらが間違っているか特定できないようにするのがポイントです。
OK例: パスワードリセット画面
登録されているメールアドレスの場合、パスワードリセット用のメールを送信しました
実際に登録されていなくても、同じメッセージを表示します。
補足: タイミング攻撃にも注意
エラーメッセージを統一しても、レスポンス時間で情報が漏れる場合があります。
ユーザーが存在する場合:
DB検索(50ms) → パスワード検証(100ms) = 合計150ms
ユーザーが存在しない場合:
DB検索(50ms) → 終了 = 合計50ms
この時間差から、ユーザーの存在を推測される可能性があります。
対策としては、ユーザーが存在しない場合でも、ダミーでパスワードハッシュの検証処理を実行して、常に同じ処理時間にする方法があります。
まとめ
ログイン画面の エラーメッセージ は、一見些細なことに思えますが、ユーザー列挙攻撃の入り口となる重要なセキュリティポイントです。
- エラーメッセージから「ユーザーの存在」を特定できないようにする
- 「メールアドレスまたはパスワードが正しくありません」のように、どちらが間違っているか分からないメッセージにする
- パスワードリセット画面も同様に配慮する
- レスポンス時間による情報漏洩にも注意する
実装自体は非常にシンプルですが、効果は絶大です。
既存のプロジェクトでも、数行のコード修正で対応できるので、ぜひ見直してみてください。


コメント