aspnet / Announcements

Subscribe to this repo to be notified about major changes in ASP.NET Core and Entity Framework Core
Other
1.66k stars 80 forks source link

Smarter defaults for Antiforgery #156

Open rynowak opened 8 years ago

rynowak commented 8 years ago

Update 3/30

We're not 100% satisfied with what we built here, so we're not going to make any changes to the default experience for validating tokens in RC2.

We're not going to ship the AntiforgeryMiddleware because we're not confident that it's our long term approach. We're still going to be looking at a solution that works with middleware, with the authentication system and can protect more of your application than just MVC.

In MVC - the @Html.BeginForm and <form> taghelper will still generate an antiforgery token by default. The [AutoValidateAntiforgeryToken] filter will be shipped in RC2 and will be available for you to use, but will not be configured by default.

Below is the original text of the announcement, but we're not making any high impact changes here for RC2.

Summary

We're making some improvements in RC2 to the Antiforgery package package to provide more sensible defaults and support usage outside of MVC. The Antiforgery package helps your protect against CSRF (also known as XSRF) vulnerabilities by requiring a server-generated token in the request.

CSRF protection is needed when a browser can make logged-in requests on a user's behalf through a form, or an image tag. A malicious website can craft a tag which will submit a request to a trusted website. This can occur when using a persistent authentication mechanism like cookie, windows-auth or basic.

With these changes we're going to detail a few strategies that can work for protecting your site from CSRF while reducing the amount of boilerplate.

History

Historically, CSRF protection has been available in MVC applications through the @Html.AntiForgeryToken() helper and [ValidateAntiForgeryToken] attribute. A developer would call @Html.AntiForgeryToken() inside every <form> element, and slap on a [ValidateAntiForgeryToken] attribute on every action method that handles user input. This boilerplate could also be generated by scaffolding, so if you were using the tools it would be done for you.

This Razor Code:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <input type="submit" value="Submit" />
}

Yields:

<form action="/" method="post">
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Huz....">
    <input type="submit" value="Submit">
</form>

And is validated by:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult HandleInput()
{
    ...
}

Uh oh

The problem with this approach of course is that you need to know about it in order to be protected. You also have to remember to put these calls on both ends (the form, and the handling action).

Changes

The first step towards improving the status quo is to make it automatic. We've made the <form> TagHelper and @Html.BeginForm include a token by default when the action is anything other than GET. You can suppress the token if you have a scenario where you don't want it.


We've also added a smarter version of [ValidateAntiForgeryToken] - [AutoValidateAntiforgeryToken].

This new attribute is a filter that expect you to apply at the global level (your whole site). The filter validates a token for unsafe (DELETE, PUT, POST, ...) HTTP methods, and does not attempt to validate a token for safe HTTP methods (GET, HEAD, OPTIONS, TRACE).

See the recommendations below. We strongly discourge making any mutations to your site's state for HTTP methods like GET.


We've also added a middleware, which plugs into the authentication system. Any request using an unsafe (DELETE, PUT, POST, ...) HTTP method will not be considered authentic unless it includes a valid token. That is, the user is not considered "logged in" unless a valid token is provided.

The advantage of using middleware is that it makes it possible to support both cookie auth (with antiforgery) and bearer-token auth (without antiforgery) on the same endpoints if desired.


Using [ValidateAntiForgery] of course still works.

Recommendations

First of all make sure that your site doesn't mutate state on any safe HTTP methods (GET, HEAD, OPTIONS, TRACE). This is a general bad practice to avoid, and can be a source of CSRF vulnerabilities.

Secondly, look for endpoints that allow anonymous user input. These are generally things like a "login" or "register" action. Place [ValidateAntiForgeryToken] on these actions if using MVC, otherwise call IAntiforgery.ValidateRequestAsync. Our templated versions of this code for user management always include [ValidateAntiForgeryToken]. This will work with any strategy.


From here consider one of the following options:

Using Antiforgery Middleware

This is the strategy that our templates (with authentication) use. The UseAntiforgery() must come after authentication middleware that you want to protect.

Requests without a valid token for a logged in user will be redirected to a logic page.

public void Configure(IApplicationBuilder app)
{
    app.UseIdentity();

    // Require a token on POST/PUT/DELETE/ETC for logged in users
    app.UseAntiforgery();

    app.UseMvcWithDefaultRoute();
}

This approach composes with any middleware and doesn't require the use of MVC. Consider this the default for new projects.

Using AutoValidateAntiforgery filter

This strategy will validate all POST/PUT/DELETE/ETC requests and give a 400 response if a valid token is not included.

public void ConfigureServices(IServiceCollection services)
{
    // Require a token on POST/PUT/DELETE/ETC for logged in users
    app.AddMvc(options =>
    {
        options.Filters.Add(new AutoValidateAntiforgeryAttribute());
    });
}

This approach is MVC specific. Use this is you want to protect a site using MVC with no authentication.

rynowak commented 8 years ago

Please use https://github.com/aspnet/Antiforgery/issues/66 for discussion, feedback and questions related to this announcement

rynowak commented 8 years ago

Added the following:

Update 3/30

We're not 100% satisfied with what we built here, so we're not going to make any changes to the default experience for validating tokens in RC2.

We're not going to ship the AntiforgeryMiddleware because we're not confident that it's our long term approach. We're still going to be looking at a solution that works with middleware, with the authentication system and can protect more of your application than just MVC.

In MVC - the @Html.BeginForm and <form> taghelper will still generate an antiforgery token by default. The [AutoValidateAntiforgeryToken] filter will be shipped in RC2 and will be available for you to use, but will not be configured by default.