Web Security Academyの「CSRF vulnerability with no defenses」ラボでは、CSRFの最も基本的な攻撃パターンを体験できます。
このラボでは、メールアドレス変更機能にCSRF対策が実装されておらず、攻撃者が用意したHTMLを踏ませるだけで、ユーザーのメールアドレスを書き換えることができます。
この記事では、このラボの流れをもとに、CSRFの仕組みとWordPressにおけるリスクを解説します。
CSRF vulnerability with no defensesラボの概要
対象の機能は以下です。
- ログインユーザーのメールアドレス変更機能
- CSRFトークンなし
- Cookieのみで認証
この状態では、外部サイトからリクエストを送るだけで、ユーザーの情報を変更できます。
CSRF攻撃が成立する3つの条件
CSRFが成立する条件はシンプルです。
- ログイン状態であること(Cookie認証)
- リクエストに予測不能な値がない
- サーバーがリクエストの正当性を検証していない
このラボは、これらすべてを満たしています。
メールアドレス変更リクエストの中身
メール変更時のリクエストは以下のようになっています。
POST /my-account/change-email HTTP/1.1
Host: lab-id.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Cookie: session=xxxxemail=test@example.comポイントは以下です。
emailパラメータのみで処理される- CSRFトークンが存在しない
- Cookieでユーザー識別している
CSRF PoCの作り方
このリクエストは、そのままHTMLに変換できます。
<html>
<body>
<form action="https://lab-id.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="attacker@evil.com">
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>このHTMLがCSRF PoCです。
CSRF攻撃の流れ
ユーザーがこのページを開くと、以下が発生します。
- フォームが自動送信される
- ブラウザがセッションCookieを自動付与
- サーバーは本人の操作と誤認
- メールアドレスが変更される
この間、ユーザーは何も操作していません。
Exploit Serverの役割|被害者のブラウザからリクエストを送る仕組み
このラボでは、CSRF攻撃の検証にExploit Serverを使用します。
一見すると、Burp Repeaterから同じリクエストを送れば再現できそうに見えますが、CSRFはそれでは成立しません。
Repeaterではなぜ成立しないのか
Repeaterから送るリクエストは自分の操作です。
そのため、自分のCookieが使われ、CSRFにはなりません。
CSRFで重要なのは被害者のブラウザ
CSRFは、被害者のブラウザからリクエストが送られて初めて成立します。
ブラウザはリクエスト時に自動でCookieを付与するため、サーバーは本人の操作と判断してしまいます。
Exploit Serverの役割
Exploit Serverは、攻撃用ページを配置するための環境です。
被害者がアクセスすると、次の流れが発生します。
- フォームが自動送信される
- 被害者のブラウザがリクエストを送る
- Cookieが自動で付与される
- サーバーが本人と誤認する
このセクションの要点
CSRFは、被害者のブラウザを利用してリクエストを送らせる攻撃です。
- Burp Repeater:リクエストの確認
- Exploit Server:攻撃の実行
この違いを理解することが重要です。
WordPressで同じ問題が起きるケース
WordPressでも同様の構造は存在します。
例
/wp-admin/profile.php(プロフィール更新)/wp-admin/options.php(設定変更)- プラグインの設定フォーム
これらの処理が以下の状態だと危険です。
- nonce(CSRFトークン)がない
- Cookieだけで認証している
- パラメータが単純
攻撃者視点で考えると
このラボのような環境では、攻撃者は以下を行うだけです。
- メール変更リクエストを取得
- HTMLに変換
- 被害者に踏ませる
特別な技術は不要で、リクエストの再現ができれば成立します。
XSSとCSRFの関係|組み合わせると何が起きるのか
CSRFは単体でも成立しますが、XSSと組み合わさるとさらに危険です。
XSSがある場合、攻撃者はサイト内部でスクリプトを実行できます。
fetch("/my-account/change-email", {
method: "POST",
credentials: "include",
body: "email=attacker@evil.com"
});この場合、ユーザーがページを見るだけで攻撃が実行されます。
CSRF対策|WordPressにおけるnonceの重要性
WordPressでは、CSRF対策として「nonce(ナンス)」が使用されています。
nonceは、リクエストごとに付与される一時的なトークンで、サーバー側で検証されます。
nonceがない場合
nonceが存在しない場合、攻撃者はリクエストをそのまま再現できます。
今回のラボのように、パラメータが単純な場合は特に危険です。
nonceがある場合
nonceが含まれると、リクエストは以下のようになります。
POST /wp-admin/profile.php
...
email=user@example.com&_wpnonce=abc123この値は予測できないため、攻撃者は正しいリクエストを再現できません。
WordPressでの実装例
WordPressでは、フォームに以下のようにnonceを埋め込みます。
wp_nonce_field('update-profile');サーバー側では、wp_verify_nonce() によって検証されます。
重要なポイント
nonceはユーザー本人かどうかではなく、正規の画面から送られたかを確認する仕組みです。
nonceを適切に使用することで、CSRF攻撃を防げます。
WordPressセキュリティ診断でのチェックポイント
CSRFは設定ミスや実装漏れで簡単に発生する脆弱性です。
WordPressサイトを診断する際は、以下のポイントを確認します。
フォームにnonceが含まれているか
WordPressでは、CSRF対策としてnonceが使用されます。
確認ポイント
- フォームに
_wpnonceが含まれているか wp_nonce_field()が使われているか
nonceがない場合、リクエストの再現が可能になります。
nonceの検証が実装されているか
フォームにnonceがあっても、サーバー側で検証していなければ意味がありません。
確認ポイント
wp_verify_nonce()が使われているか- 検証失敗時に処理が中断されるか
重要な操作がPOSTで送信されているか
設定変更などの重要な処理がGETで実装されている場合、CSRFのリスクが高まります。
確認ポイント
- 状態変更系処理がPOSTになっているか
- URLパラメータだけで処理されていないか
外部からリクエストを再現できないか
Burp Suiteなどを使い、リクエストの再現性を確認します。
確認ポイント
- トークンなしでリクエストが通るか
- パラメータが単純すぎないか
プラグインの実装を確認する
CSRFはテーマやプラグインの実装ミスで発生することが多いです。
確認ポイント
- 独自フォームにnonceがあるか
- AJAX処理でnonce検証が行われているか
CSRFは「リクエストが再現できるかどうか」を基準に判断するのがポイントです。
まとめ|CSRFはブラウザの自動送信を悪用する攻撃
このラボのポイントは以下です。
- Cookieだけの認証は危険
- リクエストが再現できると攻撃可能
- 被害者のブラウザが勝手にリクエストを送る
CSRFは難しい攻撃ではなく、設計ミスで簡単に成立します。
WordPressでもnonceを適切に使わないと、同じ問題が発生します。
