g.pickardou
g.pickardou

Reputation: 35843

Is anti forgery token added automatically, even without explicit [AutoValidateAntiforgeryToken]?

Context

I've noticed that after creating a new ASP.NET Core Razor page application in VS 2019 from its out of the box template, even the purest html form with the purest model class renders output with <input name="__RequestVerificationToken" type="hidden" value="...">

Question

Am I missing something and there is somewhere an explicit attribute/statement which instructs ASP.NET Core to add anti forgery or now this is the default? (which makes using [AutoValidateAntiforgeryToken] obsolete)

...or...

It is just the <input name="__RequestVerificationToken" type="hidden" value="..."> which is rendered always unconditionally and with the [AutoValidateAntiforgeryToken]I can turn on the server side validation against it? This case how can I smoke test if validation is in effect or not?

Sample Code

@page
@model TestFormModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <form method="post">
        <input type="text" name="myinput"/>
        <input type="submit" value="Submit" />
    </form>
</div>

//[AutoValidateAntiforgeryToken]
public class TestFormModel : PageModel
{
    private readonly ILogger<TestFormModel> _logger;

    public TestFormModel(ILogger<TestFormModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {

    }

    public void OnPost()
    {

    }
}

Upvotes: 4

Views: 5327

Answers (3)

Asons
Asons

Reputation: 87191

For the later Core versions (6,7 and maybe earlier), here's what the documentation states regarding when/if a token will be generated automatically:

The automatic generation of antiforgery tokens for HTML form elements happens when the <form> tag contains the method="post" attribute and either of the following are true:

  • The action attribute is empty (action="").
  • The action attribute isn't supplied (<form method="post">).

That mean that if to set a form's action attribute to a custom value, the "Antiforgery" element won't be injected automatically.

Here are a few ways one can do in those cases to have one injected:

  • Add the tag helper asp-antiforgery="true" to the form element
  • Add @Html.AntiForgeryToken() within the form element
  • Add @inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf to the view and
    <input id="__RequestVerificationToken" type="hidden" value="@Xsrf.GetAndStoreTokens(Context).RequestToken" /> within the form element
  • Use the submit element's formaction attribute instead of the form's.

Upvotes: 3

Mattman85208
Mattman85208

Reputation: 2090

For .Net 3.1 the form helper does add the validation token to forms when you use it like <form asp-action="...

With asp.net core 3.1 with a form that does not use asp-action and or asp-controller like:

<form asp-action="Index" asp-controller="Home" method="post">

and uses this:

<form action="Index" method="post">

To include this: (in the form {before the closing form: })

<input name="__RequestVerificationToken" type="hidden" value="..." />

I just add this to the form:

asp-antiforgery="true"

like:

<form action="Index" method="post" asp-antiforgery="true">

Always works for me

This does not work for me:

<input name="__RequestVerificationToken" type="hidden" value="{{token}}" />

I just get that exact thing which doesn't have the token. Of course you then need the decorator before your method like:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Update(...

Hope that helps someone searching for how to include the RequestVerificationToken or ValidateAntiForgeryToken

Upvotes: 0

Adam Vincent
Adam Vincent

Reputation: 3821

Previously in .NET Framework versions of ASP.NET you did have to opt-in to anti-forgery token usually with an attribute.

[ValidateAntiForgeryToken]
public ActionResult Save(Product product)
{
  db.Product.Add(product);
  Return View();
}

In ASPNET Core this automagically included in the Form Tag Helper. So any time your CSHTML includes a FORM element, the hidden field is included for you by the ASPNET Core runtime.

The basis for including this by default is the mantra of "Convention over configuration". By convention, 80+% of developers would opt to protect their application against CSRF attacks. If you wish to go against the convention, you can find the option to opt out in the conventions helper in the ConfigureServices portion of your Startup class.

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages()
            .AddRazorPagesOptions(options =>
            {
                options.Conventions
                       .ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
            });
}

This blog post goes in further detail specific to Razor Pages, options and usage scenarios.

Update - Response to comment

If you read the a code, you may notice that there is no taghelper. – g.pickardou

There is indeed a tag helper. In a new Razor Pages project template you can find the tag helpers are included in the _ViewImports.cshtml file here:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

We can validate that your <form /> element, as written in the OP is invoking an ASP.NET tag helper as follows:

    <form method="post">
        <input type="text" name="myinput"/>
        <input type="submit" value="Submit" />
    </form>

If we inspect the page source on this, you will see the result

<form method="post">
    <input type="text" name="myinput" />
    <input type="submit" value="Submit" />
<input name="__RequestVerificationToken" type="hidden" value="{{token}}" />
</form>

Now, if we use the syntax to opt out of individual tag helpers

<!form method="post">
    <input type="text" name="myinput" />
    <input type="submit" value="Submit" />
</!form>

And again inspect the page source we can clearly see we have explicitly opted out of this tag helper.

<form method="post">
    <input type="text" name="myinput" />
    <input type="submit" value="Submit" />
</form>

Upvotes: 9

Related Questions