1. ユーザ列挙の手法 #enumeration
ユーザ列挙の入口は、ログインフォームだけではありません。次のような場所が典型的な漏洩源です:
- ログイン画面のエラーメッセージ — 「ユーザ不在」と「パスワード不一致」を区別している
- 新規登録フォームの「既に登録済み」メッセージ — 「このメールアドレスは既に登録されています」
- パスワードリセット画面 — 「リセットメールを送りました」vs「該当するアカウントが見つかりません」
- レスポンス時間の差 — DB 検索 + パスワードハッシュ検証 vs DB 検索のみ
- HTTP ステータスコードの差 — 200 と 404 の使い分けが本人特定に使える
全ての入口で「ユーザ存在の有無」を漏らさない統一的な応答を返す必要があります。
2. レスポンス時間からの漏洩 #timing-leak
エラーメッセージは統一したが、サーバ内部のロジックがこうなっていたら:
if user = lookup_user(email):
if password_hash_verify(user.password_hash, input_password):
login_success()
else:
return "メールアドレスまたはパスワードが正しくありません"
else:
return "メールアドレスまたはパスワードが正しくありません"
ユーザが存在する場合はハッシュ検証(bcrypt や Argon2 で 100ms〜500ms かかる)が走り、存在しない場合は即座にエラーが返る。応答時間の差で「ユーザの存在」が漏れます。
// タイミング攻撃対策
user = lookup_user(email)
if user:
valid = password_hash_verify(user.password_hash, input_password)
else:
// ダミーのハッシュ検証で時間を消費
password_hash_verify(DUMMY_HASH, input_password)
valid = false
if not valid:
return "メールアドレスまたはパスワードが正しくありません"
ユーザの存在に関わらず常にハッシュ検証を実行することで、レスポンス時間を均一化します。
3. ブルートフォース #brute-force
ユーザ列挙で得たメールアドレス一覧に対して、よくあるパスワード(password123、qwerty、password1 等)を片っ端から試す攻撃。
ブルートフォースを成立させる条件は2つ:
- ターゲットアカウントが存在する(ユーザ列挙の結果)
- レート制限がない、または弱い
レート制限がなければ、単純なパスワード一覧 1万件を1秒で試行可能。Have I Been Pwned 等の漏洩データから流通している弱いパスワード辞書は数百万件あります。
4. クレデンシャル・スタッフィング #credential-stuffing
人は同じパスワードを複数のサービスで使い回す傾向があります。攻撃者は別サービスの漏洩リスト(数億件規模が流通)を入手し、そのままうつろい EC のログインフォームで試行します。
ブルートフォースとの違い:
- ブルートフォース — 1ユーザ × 多パスワード。レート制限で防げる
- クレデンシャル・スタッフィング — 多ユーザ × 1ペア × 同時並行。1アカウントあたり試行回数が少ないので、単純なレート制限を回避
対策:
- IP 単位だけでなく「グローバルな失敗率」も監視(短時間で異常な失敗数が出ていれば攻撃を疑う)
- パスワード変更時に Have I Been Pwned API で漏洩リストとの一致をチェックして再利用を拒否
- MFA を必須化(ID/パスワードだけでは認証完了しない)
5. レート制限 #rate-limit
ブルートフォース対策の基本。実装には複数の軸を組み合わせます:
- IP 単位 — 同一 IP からの失敗試行を制限。VPN や Tor で回避される弱点あり
- アカウント単位 — 同一アカウントへの失敗試行を制限。ロックアウトされる被害ユーザ自身に注意
- グローバル — システム全体で「短時間に大量の認証失敗」を検知
具体的な制限値の例:
- 1分あたり5回まで → 6回目以降は CAPTCHA
- 15分あたり10回まで → 一時ロックアウト(30分)
- 同一アカウントへ24時間で20回失敗 → アカウントロック(管理者解除が必要)
過度に厳しいロックアウトは、攻撃者が DoS として利用する(意図的に他人のアカウントを大量にロックする)リスクもあるので、CAPTCHA や時限ロック等で被害を限定するのが実務的。
6. 多要素認証(MFA) #mfa
パスワードだけでは突破される前提で、別カテゴリの認証要素を追加で要求する設計。詳細は KB 01 §2 参照。
実装の選択肢を強さ順に並べると:
- FIDO2 / WebAuthn(YubiKey、Passkey 等) — フィッシング耐性あり、最強
- TOTP(Google Authenticator 等) — オフライン動作、SIM スワップ攻撃を受けない
- プッシュ通知(Microsoft Authenticator 等) — UX 良好、ただし「MFA 疲労攻撃」のリスク
- SMS/メールのワンタイムコード — 一定の効果はあるが SIM スワップやメール乗っ取りで突破される
MFA 自体は強力ですが、実装ミスで素通りされる事例があります:
・「MFA をスキップ」の隠しエンドポイントが残っている
・MFA コード検証時にレート制限がなく、6桁の総当たりで突破される
・「次回からスキップ」を任意の Cookie 値で実装(改ざん可能)
・MFA 設定変更時に MFA 確認を要求しない(攻撃者が乗っ取った後に MFA を勝手に再設定)
これらは Lab 03〜05 で扱う予定の典型的な落とし穴です。