今回は、Web Security Academyのラボ「2FA broken logic」 をもとに、二要素認証の設計ミスについて解説します。
2段階認証(2FA)は、パスワードに加えてワンタイムコードを入力することで、アカウントの安全性を高める仕組みです。
しかし、このラボでは、2FAの設計にロジック上の問題があり、本来アクセスできないはずのユーザーアカウントにログインできてしまいます。
一見安全そうな2FAでも、設計ミスがあると簡単に突破されることがあります。
Web Security Academy「2FA broken logic」ラボの概要
このラボでは、次のようなログインフローが実装されています。
- ユーザー名とパスワードでログイン
- メールで2FAコードを受け取る
- そのコードを入力するとログイン完了
しかし、2FA認証処理の内部では、どのユーザーの認証コードを確認するかをリクエストのパラメータで判断しているという問題があります。
この仕組みを悪用すると、別ユーザー(Carlos)の認証コードを総当たりで突破する攻撃が可能になります。
2FAを突破できる攻撃の流れ
まず、この攻撃の流れを整理します。
ログイン画面
↓
攻撃者がログイン処理を観察
↓
2FA確認リクエストのパラメータを書き換える
↓
別ユーザーの認証コードをブルートフォース
↓
被害者アカウントにアクセス成功
このラボでは、HTTPリクエストのverifyパラメータを変更することで、認証対象のユーザーを切り替えられてしまいます。
つまり、本来は、自分の認証コードだけ確認すべきなのに、別ユーザーの認証コードも試せる状態になっています。
なぜ2FAが突破されるのか|認証ロジックの設計ミス
この脆弱性が起きる原因は、2FA認証の対象ユーザーをサーバー側で固定していないことです。
通常、2FA認証では次の流れになります。
- ユーザーがログイン
- サーバーが「このユーザーの2FA認証中」とセッションに記録
- そのユーザーのコードだけ検証
しかし、このラボでは、
POST /login2
verify=carlos
mfa-code=1234
のように、リクエストのパラメータだけで認証対象を決めてしまっています。
その結果、攻撃者は次のことができてしまいます。
- verify=carlos に変更
- 認証コードを総当たり
- Carlosのアカウントにログイン
つまり、2FAの「認証対象ユーザー」が信頼できない入力で決まっているという設計ミスです。
「2FA broken logic」の意味をわかりやすく解説
ラボ名 「2FA broken logic」 を分解すると次の意味になります。
- 2FA:二要素認証
- broken:壊れている / 正しく機能していない
- logic:処理の設計やルール
つまりこのラボは「2FAの処理ロジックが壊れている脆弱性」という意味です。
暗号の問題ではなく、設計ミスによって認証が成立してしまう典型的な例です。
なぜこれはビジネスロジック脆弱性なのか
この問題は、SQLインジェクションやXSSのような技術的なバグではありません。
原因は アプリケーションの設計ルールのミス です。
本来のログインの前提は次の通りです。
- ユーザーAはユーザーAの2FAだけ確認できる
- 他人の認証コードを試すことはできない
しかし、このサイトでは、
- verify パラメータを書き換える
- 別ユーザーの認証コードを試せる
という状態になっています。
つまり、ログインのルールが壊れている。これがビジネスロジック脆弱性です。
WordPressサイトで起きた場合の具体例(会員サイト・管理画面)
では、この問題をWordPressサイトで考えてみます。
例えば、会員サイトやECサイトで次のような2FAを導入していたとします。
- ユーザー名とパスワードでログイン
- メールでワンタイムコード送信
- コードを入力してログイン
もし、2FA確認APIが次のような仕様だったら危険です。
POST /wp-login-2fa
user=carlos
code=123456
この場合、攻撃者が次のようなリクエストを送ることができます。
user=carlos
code=000001
user=carlos
code=000002
これを繰り返すと、管理者アカウントの2FAを突破できる可能性があります。
ログイン画面
↓
2FAコード入力画面
↓
APIで user パラメータを送信
↓
攻撃者が user=admin に変更
↓
管理者の2FAコードを総当たり
このような実装だと、WordPress管理画面が乗っ取られる可能性があります。
WordPressで2FAを安全に実装するための対策
WordPressや会員サイトでは、次の対策が重要です。
まず重要なのは、認証対象ユーザーをパラメータで決めないことです。
正しい設計は次の通りです。
- ログイン成功時にユーザーIDをセッションに保存
- 2FAではそのユーザーのコードだけ確認
- リクエストパラメータを信用しない
また、次の対策も有効です。
- 2FA入力回数制限
- IP制限
- 短時間での試行回数ブロック
特にWordPressでは、
- Wordfence
- WP 2FA
などのプラグインを使うことで安全に実装できます。
認証設計の視点で見ると何が問題だったのか
このラボの問題は、認証状態の管理がサーバー側で行われていないことです。
本来は、
- ログイン成功
- 2FA待ち状態
- 認証完了
という状態管理が必要です。
しかしこのラボでは、リクエストパラメータだけで認証対象を決めているため、攻撃者が簡単に書き換えられてしまいました。
これは典型的な認証フローの設計ミスです。
2FA設計ミスを防ぐチェックリスト
ログイン機能を設計するときは、次のポイントを確認する必要があります。
- 2FA対象ユーザーはセッションで管理しているか
- リクエストパラメータでユーザーを指定できないか
- 2FAコードに試行回数制限があるか
- 認証コードの有効期限が短いか
- 別ユーザーの認証コードを試せない設計になっているか
このチェックだけでも、多くの認証バグを防ぐことができます。
セキュリティ診断で確認すべきポイント
セキュリティ診断では、次のポイントを確認します。
- 2FA確認APIのパラメータ
- ユーザーIDがリクエストで指定できないか
- 認証コードの総当たりが可能か
- 認証コードの有効期限
- 認証試行回数の制限
特にBurp Suiteを使うと、パラメータ改ざんによる認証バイパスを簡単に確認できます。
まとめ
今回のラボでは、2FAの認証対象ユーザーをパラメータで指定できる設計ミスが原因で、別ユーザーのアカウントにログインできてしまいました。
ポイントは次の通りです。
- 2FAでも設計ミスがあると突破される
- 認証対象ユーザーはサーバー側で管理する
- パラメータの値を信用してはいけない
WordPressサイトでも、会員サイトやECサイトではログインフローの設計ミスがそのまま乗っ取りにつながることがあります。
2FAを導入しているから安全、とは限りません。
認証の設計そのものが正しいかどうかを確認することが重要です。
よくある疑問
Q. 2FAがあればアカウントは安全ですか?
必ずしも安全とは限りません。
今回のラボのように、設計ミスがあると簡単に突破されることがあります。
Q. WordPressでも同じ問題は起きますか?
標準のWordPressログインでは起きにくいですが、独自ログインや会員サイト機能を実装している場合は注意が必要です。
Q. なぜ認証コードを総当たりできたのですか?
認証コードの試行回数制限がなかったためです。
回数制限があれば、この攻撃は成立しにくくなります。
Q. 2FAを安全に実装するにはどうすればいいですか?
次のポイントが重要です。
・認証対象ユーザーはセッションで管理
・認証コードの試行回数制限
・コードの有効期限を短くする
