# 認証の脆弱性の完全攻略【2026】ユーザー名列挙・総当たり・2FAバイパス・パスワードリセット — 公式ドキュメント忠実版

> 認証（ログイン）機構の脆弱性と攻撃手法を、PortSwigger Web Security Academyに忠実に深掘り。ユーザー名列挙（メッセージ差・応答時間差）、総当たりとレート制限の回避、アカウントロックの抜け穴、多要素認証（2FA/MFA）のバイパス、パスワードリセットの汚染、Remember Me/パスワード変更の不備、そしてレート制限・一定応答・MFA・安全なリセット設計による根本対策までを、自分のラボ限定で解説します。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: セキュリティ, ホワイトハッカー, 認証, 脆弱性診断, Webセキュリティ
- URL: https://tomodahinata.com/blog/authentication-vulnerabilities-brute-force-2fa-bypass-attack-guide
- カテゴリ: 実践Webハッキング技法
- 総合ガイド: https://tomodahinata.com/blog/web-application-hacking-techniques-methodology-owasp-portswigger-guide

## 要点

- 認証の穴は『推測できる・列挙できる』ところに生まれる。ユーザー名列挙はエラーメッセージの差・応答時間の差・HTTPステータスの差から成立する。まず有効なユーザー名を特定し、次にパスワードを総当たりする2段構え
- 総当たり対策の不備が狙われる：IPベースのレート制限はIPローテーションやX-Forwarded-Forで回避され、アカウントロックはユーザーを分散させる『パスワードスプレー』で回避される。ロック自体がユーザー名列挙の信号にもなる
- 多要素認証(2FA/MFA)のバイパス：検証ロジックの不備（2要素目を飛ばして遷移できる）、OTPの総当たり（レート制限・試行回数制限がない）、検証対象ユーザーの取り違え。MFAは『正しく実装されて初めて』効く
- パスワードリセットは認証の裏口。推測可能なトークン、Hostヘッダ汚染による攻撃者ドメインへのリセットリンク送信、ユーザー識別子の差し替えで他人のパスワードを奪える
- 根本対策：一定のエラー応答・応答時間でユーザー名列挙を塞ぐ、堅牢なレート制限とMFA、推測不能で短命・単回・ユーザー束縛のリセットトークン、HostヘッダではなくサーバーURLを信頼する

---

認証は、アプリのセキュリティの**最前線**です。ここが破れれば、その先の認可も暗号も意味をなしません。[PortSwigger](https://portswigger.net/web-security/authentication) が言う通り「認証の脆弱性は、攻撃者に機密データへのアクセスを許し」、特権アカウントを奪われればアプリ全体が乗っ取られます。本記事は、その攻撃手法を公式に忠実に解説します。

> **絶対の前提:** 総当たり・列挙・リセット汚染は、いずれも**強い侵襲性**を持ちます。実行は [合法ラボ](/blog/ethical-hacking-home-lab-kali-juice-shop-ctf-self-study-roadmap-guide) または書面で許可されたスコープでのみ。無許可のログイン試行は、それ自体が不正アクセス行為です（→ [法律ガイド](/blog/ethical-hacker-law-japan-unauthorized-access-act-active-cyber-defense-disclosure-guide)）。地図は [ピラー](/blog/web-application-hacking-techniques-methodology-owasp-portswigger-guide)。

---

## 1. ユーザー名列挙 — 攻撃の第一段

総当たりの前に、**「存在する有効なユーザー名」を確定**させると効率が跳ね上がります。アプリは、しばしば**わずかな差**でユーザーの存在を漏らします。

| 漏洩の信号 | 例 |
|---|---|
| **メッセージの差** | 「ユーザー名が不正」 vs 「パスワードが不正」 |
| **応答時間の差** | 存在するユーザーだけハッシュ照合が走り、応答が遅い |
| **HTTPステータス/微妙な文言差** | 末尾の句点の有無、リダイレクト先の違い |

```http
# Burp Intruder で username を辞書にして送り、レスポンスの差分（長さ・文言・時間）を観察
POST /login HTTP/1.1
Host: lab.example
Content-Type: application/x-www-form-urlencoded

username=§candidate§&password=wrongpass
```

[Burp Intruder](/blog/burp-suite-getting-started-proxy-repeater-intruder-web-security-testing-guide) の **Sniper** 攻撃で `username` 位置だけを回し、**レスポンス長や応答時間の外れ値**から有効ユーザーを割り出します。

---

## 2. 総当たり（ブルートフォース）と保護の回避

有効ユーザー名が判明したら、パスワードを総当たりします。問題は**保護機構の不備**です。

### 2.1 IPベースのレート制限の回避

「同一IPから一定回数失敗したらブロック」は、ヘッダ偽装やIPローテーションで回避され得ます。

```http
# X-Forwarded-For を毎回変えて、IPベースのカウンタを欺く（脆弱な実装で有効）
X-Forwarded-For: 1.2.3.4
```

### 2.2 アカウントロックの抜け穴 — パスワードスプレー

「1ユーザーがN回失敗でロック」は、**多数のユーザーに同じ弱いパスワードを1回ずつ**試す**パスワードスプレー**で回避されます。各ユーザーの失敗回数はロック閾値に届きません。

```text
# 縦に弱いパスワードを固定し、横に大量ユーザーを試す（Pitchfork/Cluster bomb的）
user001 : Password1!
user002 : Password1!
...                      ← どのユーザーもロックされない
```

さらに、**ロックされたという応答自体**が「このユーザーは存在する」という列挙の信号になります。

---

## 3. 多要素認証（2FA/MFA）のバイパス

MFAは強力ですが、**正しく実装されて初めて**効きます。PortSwigger が挙げる典型的な穴：

### 3.1 検証ロジックの欠落（2段目を飛ばす）

1段目（パスワード）成功後に発行されるセッションが、**2段目未完了でも保護リソースへ到達できる**場合。2FA入力画面をスキップして、直接遷移先URLを叩くと通ってしまう。

```http
# 2FAページを経由せず、ログイン後のページへ直接アクセスして通るか確認
GET /my-account HTTP/1.1
Host: lab.example
Cookie: session=<1段目だけ通したセッション>
```

### 3.2 OTPの総当たり

検証コード（OTP）に**試行回数制限・レート制限がない**と、4〜6桁を総当たりできます。[Burp Intruder](/blog/burp-suite-getting-started-proxy-repeater-intruder-web-security-testing-guide) で `0000`〜`9999` を回すだけで突破され得ます。

### 3.3 ユーザーの取り違え

2段階目の検証が、**1段目のユーザーと別のユーザーのコード**を受け付けてしまう実装ミス。アカウント識別をクライアント任せにすると起きます。

---

## 4. その他の機構 — リセット・Remember Me・変更

### 4.1 パスワードリセットの汚染（裏口）

パスワードリセットは「本人確認を一時的に緩める」ため、認証の**裏口**になりやすい。

- **推測可能なトークン**：連番・タイムスタンプ・短いトークンは予測される。
- **Hostヘッダ汚染**：リセットリンクの生成に **`Host` ヘッダ**を使っていると、攻撃者が `Host: evil.example` を送り、**被害者宛のメールに攻撃者ドメインのリンク**を仕込める。被害者がクリックするとトークンが攻撃者に渡る。
- **識別子の差し替え**：リセット確定リクエストの `username`/`userId` を他人に変えられると、他人のパスワードを設定できる。

```http
# Hostヘッダ汚染：被害者宛リセットメールのリンクが攻撃者ドメインを指すよう仕込む
POST /forgot-password HTTP/1.1
Host: evil-attacker.example          ← サーバーがこれを信頼してリンク生成すると致命的
Content-Type: application/x-www-form-urlencoded

username=victim
```

### 4.2 Remember Me / パスワード変更

「ログイン状態を保持」のトークンが**推測可能**（ユーザー名のハッシュ等）だと偽造される。パスワード変更が**現行パスワードを確認しない**と、セッション奪取後の永続化に使われます。

---

## 5. 【守る側】根本対策

攻撃面を理解したら、設計で塞ぎます。PortSwigger と [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html) の要諦：

```ts
// ✅ ユーザー名列挙を防ぐ：成否で「同一の」メッセージ・同等の処理時間を返す
async function login(username: string, password: string) {
  const user = await findUser(username);
  // ユーザーが存在しなくても必ずハッシュ照合を走らせ、応答時間を一定化（タイミング差を消す）
  const hash = user?.passwordHash ?? DUMMY_HASH;
  const ok = await verifyPassword(password, hash); // Argon2id 等
  if (!user || !ok) {
    // 列挙を許さない一定の文言（どちらが違うかを明かさない）
    throw new AuthError("ユーザー名またはパスワードが正しくありません");
  }
  // ...
}
```

設計原則：

- **列挙を塞ぐ**：成否で**同一メッセージ・同等の応答時間・同一ステータス**。
- **堅牢なレート制限**：IPだけでなく**アカウント単位 + グローバル**で。`X-Forwarded-For` を信頼しない。サーバーレスでの正しいレート制限は [専用ガイド](/blog/nextjs-serverless-rate-limiting-vercel-guide)。
- **MFAを正しく実装**：2段目完了まで保護リソースへ到達させない。OTPに**試行回数制限**。コードは短命・単回・**1段目ユーザーに束縛**。
- **パスワードリセットの安全化**：**推測不能（CSPRNG）で長く・短命・単回・ユーザー束縛**のトークン。リンク生成に **`Host` ヘッダを使わず、サーバー側の正規URLを信頼**する（[HTTP Host header攻撃](https://portswigger.net/web-security/host-header)対策）。
- **パスワード強度とハッシュ**：Argon2id等で保存し、弱いパスワードを拒否。詳細は [パスワードハッシュ・暗号ガイド](/blog/password-hashing-argon2-encryption-key-management-applied-cryptography-guide)。
- **セッション**：認証後にセッションIDを再生成、`HttpOnly`/`Secure`/`SameSite` を付与。

認証基盤そのものをマネージドに寄せる選択（Cognito/Auth0/Clerk/Supabase Auth）は [認証プラットフォーム選定](/blog/auth-platform-selection-2026-cognito-auth0-clerk-supabase) を参照。**「認証は自前実装しない」**のが、多くのプロジェクトで最も安全な判断です。

---

## 6. まとめ

- **列挙→総当たりの2段構え**：まず有効ユーザー名を、メッセージ差・時間差から特定。
- **保護機構は回避される**：IP制限はヘッダ偽装、ロックはパスワードスプレーで。
- **MFAは実装次第**：2段目スキップ・OTP総当たり・ユーザー取り違えに注意。
- **リセットは裏口**：推測可能トークン・Hostヘッダ汚染・識別子差し替え。
- **根本対策**：一定応答で列挙封じ + 堅牢なレート制限 + 正しいMFA + 安全なリセット + 強ハッシュ。

次は、テンプレートエンジンを乗っ取ってRCEに至る [SSTIの完全攻略](/blog/server-side-template-injection-ssti-rce-detection-exploitation-guide) へ。

---

### 参考（公式一次情報）

- [PortSwigger: Authentication](https://portswigger.net/web-security/authentication) ／ [2FA](https://portswigger.net/web-security/authentication/multi-factor) ／ [HTTP Host header attacks](https://portswigger.net/web-security/host-header)
- [OWASP: Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html) ／ [Forgot Password Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html)
- [NIST SP 800-63B（電子的認証ガイドライン）](https://pages.nist.gov/800-63-3/sp800-63b.html)
