ASP.NET MVC における CSRF 攻撃対策:ValidateAntiForgeryToken の活用方法

カスタム属性によるトークン検証

標準の ValidateAntiForgeryToken 属性の代わりに、独自の検証ロジックを持つカスタム属性を作成することも可能です。以下は、リクエストの認証を処理するカスタム属性の例です。

public class CustomValidateAntiForgeryToken : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext context)
    {
        var httpRequest = context.HttpContext.Request;
        // POSTリクエストの場合のみ検証を実行
        if (httpRequest.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase))
        {
            // クッキーからトークンを取得
            var antiForgeryCookie = httpRequest.Cookies[AntiForgeryConfig.CookieName];
            var cookieValue = antiForgeryCookie?.Value;

            // リクエストボディからトークンを取得
            var formToken = httpRequest.Form["__RequestVerificationToken"];

            // トークンを検証。検証に失敗すると例外がスローされます。
            try
            {
                AntiForgery.Validate(cookieValue, formToken);
            }
            catch (Exception ex)
            {
                // 検証エラー時の処理
                context.Result = new ContentResult
                {
                    Content = "セキュリティ上の理由により、リクエストを処理できませんでした。",
                    ContentEncoding = System.Text.Encoding.UTF8
                };
                return;
            }
        }
    }
}

このカスタム属性をコントローラーのアクションメソッドに適用します。

[HttpPost]
[CustomValidateAntiForgeryToken]
public ActionResult SubmitData(int userId)
{
    // トークンが有効な場合、ここに到達します。
    return View();
}

標準属性の使用とAJAXでの実装

ASP.NET MVC と ASP.NET Core の両方で標準の ValidateAntiForgeryToken 属性が提供されています。これを利用する場合、フロントエンドからトークンを正しく送信する必要があります。

まず、HTMLフォームにトークンを埋め込みます。

<form id="myForm">
    @Html.AntiForgeryToken()
    <input type="text" name="userName" placeholder="ユーザー名を入力" />
    <input type="text" name="userAddress" placeholder="住所を入力" />
    <input type="submit" value="送信" />
</form>

次に、JavaScript(jQueryを使用)でフォームをAJAX経由で送信する例です。フォーム内のトークンを取得し、リクエストデータに含めます。

// フォーム内のCSRFトークンを取得する関数
function getCsrfToken() {
    return $('[name=__RequestVerificationToken]').val();
}

// フォームの送信イベントを処理
$('#myForm').submit(function(event) {
    event.preventDefault(); // フォームの通常の送信を防止

    var formData = $(this).serializeArray();
    var csrfToken = getCsrfToken();

    // トークンをリクエストデータに追加
    formData.push({ name: "__RequestVerificationToken", value: csrfToken });

    $.ajax({
        url: '/Home/ProcessForm',
        type: 'POST',
        data: formData,
        dataType: 'json',
        success: function(response) {
            alert('成功: ' + response.message);
        },
        error: function(xhr, status, error) {
            alert('エラー: ' + error);
        }
    });
});

バックエンドでは、標準の属性を使用して検証を自動化できます。検証に失敗すると、フレームワークが自動的に400 Bad Request エラーを返します。

public class FormModel
{
    public string UserName { get; set; }
    public string UserAddress { get; set; }
}

[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult ProcessForm(FormModel model)
{
    // トークンが有効であれば、ここに到達します。
    return Json(new { message = "フォームが正常に処理されました。" });
}

タグ: ValidateAntiForgeryToken ASP.NET MVC ASP.NET Core csrf C#

6月15日 16:49 投稿