aspnet / antiforgery Goto Github PK
View Code? Open in Web Editor NEW[Archived] AntiForgery token feature for ASP.NET Core. Project moved to https://github.com/aspnet/AspNetCore
License: Apache License 2.0
[Archived] AntiForgery token feature for ASP.NET Core. Project moved to https://github.com/aspnet/AspNetCore
License: Apache License 2.0
This question is related to how caching and Antiforgery was handled for #105.
Looking at
Explicitly set the cache headers to 'no-cache'. This could override any user set value but this is fine as a response with antiforgery token must never be cached.
and thus SetDoNotCacheHeaders()
...
@JunTaoLuo said ref ...
The proposal is to disable caching when antiforgery is used regardless of whether cookies are being set.
RFC 7234 doesn't guarantee that storage will not occur tho ...
5.2.1.4. no-cache
The "no-cache" request directive indicates that a cache MUST NOT use a stored response to satisfy the request without successful validation on the origin server.
Wondering: Why doesn't Antiforgery set no-store
rather than no-cache
?
Currently, SaveCookieTokenAndHeader
always replaces the X-Frame-Options
header with its own value, even if a stricter header has already been added to the response headers by another middleware (e.g NWebsec).
Of course, SuppressXFrameOptionsHeader
could be used to prevent SaveCookieTokenAndHeader
from updating the X-Frame-Options
header but I believe it would be better to add a check to avoid overriding it in this case, specially if the existing header is stricter (i.e uses DENY).
/cc @blowdart
Office would like this. You can do it by using a time limited data protection payload.
https://docs.asp.net/en/latest/security/data-protection/consumer-apis/limited-lifetime-payloads.html
When setting the cookie token and headers on a response that uses antiforgery, caching should be disabled to prevent the content from being cached.
Adding the cache control headers Cache-Control: no-cache, no-store
should be sufficient.
I am implementing AntiForgeryToken my login form.
When I run project, its call Account/Login Get mothod and return view() i.e login.cshtml
In login.cshtml view page, I have
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form1" }))
{
@Html.AntiForgeryToken(); // throw exception
<label class="username_style" for="UserName"></label>
@Html.TextBoxFor(m => m.UserName, new { placeholder = "UserName", autofocus = true })
<label class="password_style" for="Password"></label>
@Html.TextBoxFor(m => m.Password, new { type = "password", placeholder = "Password" })
<p class="msg error">@Html.ValidationSummary(false, "", new { @class = "msg error" })</p>
<input type="submit" name="login" value="Login" id="btnLogin" />
<p><a href="javascript:void(0)" class="elink">Forgot Password?</a></p>
}
When server return login.cshtml page I got this exception
I am implementing AntiForgeryToken my login form.
When I run project, its call Account/Login Get mothod and return view() i.e login.cshtml
In login.cshtml view page, I have
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form1" }))
{
@Html.AntiForgeryToken(); // throw exception
<label class="username_style" for="UserName"></label>
@Html.TextBoxFor(m => m.UserName, new { placeholder = "UserName", autofocus = true })
<label class="password_style" for="Password"></label>
@Html.TextBoxFor(m => m.Password, new { type = "password", placeholder = "Password" })
<p class="msg error">@Html.ValidationSummary(false, "", new { @class = "msg error" })</p>
<input type="submit" name="login" value="Login" id="btnLogin" />
<p><a href="javascript:void(0)" class="elink">Forgot Password?</a></p>
}
When server return login.cshtml page
Server cannot append header after HTTP headers have been sent.
I can not figure out how to solve this error.
Thank you,
When you put your application to virtual directory named myvirtualpath in IIS, antiforgery cookie is still using / as path and not /myvirtualpath.
I looked at the AntiforgerySample but I'm still confused how this works in an Angular SPA environment (where the majority of [ValidateAntiforgeryToken]
is declared on the backend WebApi in my project).
I have followed the same as the sample, but I will also note I have added Identity, which I think also adds the Antiforgery service for itself(?).
I have done a login page and a logoff page, where the cshtmls are 'dumb' and I have HttpPost methods LogIn and LogOff [ValidateAntiforgeryToken]
as WebApi methods that the angular controller calls.
The first time it generates the token and I can successfully log on in the Login page.
However, any subsequent WebApi calls that have [ValidateAntiforgeryToken]
(eg. my LogOff WebApi method), I keep getting The provided antiforgery token was meant for a different claims-based user than the current user.
Looking at Fiddler, I see 3 cookie tokens sent on request (each with different values):
.AspNetCore.Antiforgery.xxxx
.AspNetCore.Identity.Application
XSRF-TOKEN
Am I missing something in my case? Do I need to override how the validation is working?
Moved from: aspnet/Mvc#1210
Scenario as mentioned in below article:
http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-(csrf)-attacks
The error message says The required anti-forgery cookie "__RequestVerificationToken" is not present
...notice that it mentions the form field name here...
services.AddSingleton<CustomAntiForgeryTokenFilter>();
//---------------------------------
public class CustomAntiForgeryTokenFilter : IAuthorizationFilter
{
private readonly AntiForgery _antiForgery;
public CustomAntiForgeryTokenFilter(AntiForgery antiForgery)
{
_antiForgery = antiForgery;
}
public void OnAuthorization(AuthorizationContext context)
{
string cookieToken = string.Empty;
string formToken = string.Empty;
string[] tokenHeaders;
if (context.HttpContext.Request.Headers.TryGetValue("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders[0].Split(':');
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
_antiForgery.Validate(context.HttpContext, cookieToken, formToken);
}
}
//---------------------------------
[ServiceFilter(typeof(CustomAntiForgeryTokenFilter), Order = 1)]
[Authorize(Order = 2)]
public class ValuesController : Controller
{
[HttpPost("api/values")]
public Person Create([FromBody]Person data)
{
return data;
}
}
Error Message
System.InvalidOperationException: The required anti-forgery cookie "__RequestVerificationToken" is not present.
at Microsoft.AspNet.Mvc.TokenProvider.ValidateTokens(HttpContext httpContext, ClaimsIdentity identity, AntiForgeryToken sessionToken, AntiForgeryToken fieldToken)
at Microsoft.AspNet.Mvc.AntiForgeryWorker.Validate(HttpContext httpContext, String cookieToken, String formToken)
at Microsoft.AspNet.Mvc.AntiForgery.Validate(HttpContext context, String cookieToken, String formToken)
at WebApplication10.CustomAntiForgeryTokenFilter.OnAuthorizationAsync(AuthorizationContext context) in C:\Users\kichalla\Documents\Visual Studio 14\Projects\WebApplication10\src\WebApplication10\CustomAntiForgeryTokenFilterAttribute.cs:line 33
at Microsoft.AspNet.Mvc.FilterActionInvoker.<InvokeAuthorizationFilter>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.FilterActionInvoker.<InvokeActionAuthorizationFilters>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.FilterActionInvoker.<InvokeExceptionFilter>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Mvc.FilterActionInvoker.<InvokeAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.ReflectedActionInvoker.<InvokeAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at Microsoft.AspNet.Mvc.MvcRouteHandler.<RouteAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Routing.Template.TemplateRoute.<RouteAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Routing.AttributeRoute.<RouteAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Routing.RouteCollection.<RouteAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Builder.RouterMiddleware.<Invoke>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Security.Infrastructure.AuthenticationMiddleware`1.<Invoke>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Security.Infrastructure.AuthenticationMiddleware`1.<Invoke>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Security.Infrastructure.AuthenticationMiddleware`1.<Invoke>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Security.Infrastructure.AuthenticationMiddleware`1.<Invoke>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.RequestContainer.ContainerMiddleware.<Invoke>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Loader.IIS.KlrHttpApplication.<ProcessRequestAsyncImpl>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Loader.IIS.HttpApplicationBase.<InvokeProcessRequestAsyncImpl>d__1.MoveNext()
On the DefaultAntiforgeryTokenStore
the AntiforgeryOptions.RequiresSsl
flag is used to configure the "secure" flag of the resulting cookie. If AntiforgeryOptions.RequiresSsl
is true, than the "secure" flag is enforced.
However, if AntiforgeryOptions.RequiresSsl
is false, nothing is done on the "secure" flag. The source code contains a comment stating that the "secure" flag is populated out of band. Where's this "out of band" place exactly? Shouldn't the "secure" flag be set accordingly to HttpRequest.IsHttps
, similar to how it is done on other components?
The current implementation enforces that if this option is enabled that the incoming request must occur over SSL. This causes an issue when you have SSL terminated on a frontend server, such as hosting a site on nginx.
The authentication system allows for the secure flag to be set regardless of the SSL state of the request. See: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNet.Authentication.Cookies/CookieAuthenticationOptions.cs and https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNet.Authentication.Cookies/CookieSecureOption.cs. With that, using the setting of 'Always' allows the cookie to be marked secure even with SSL termination in front of aspnet.
Please consider updating the implementation to be more consistent with the authentication system, which will also support more hosting scenarios.
Thanks!
We should add logging
Some ideas:
Thinking warning is right for failures, because generally this is a app configuration issue.
Rename ServiceCollectionExtensions
to AntiforgeryServiceCollectionExtensions
so that the type name is not ambiguous across other assemblies.
I'd like to request a DELETE using a button on a form wired up to ...
$.ajax({
url: '/delete/' + resource,
type: 'DELETE',
async: true,
cache: false,
success: function(result) {
...
},
error: function(jqXHR, exception) {
...
}
});
... with ...
[HttpDelete("/delete/{resource}")]
public async Task<HttpStatusCode> Delete(string resource)
{
...
return HttpStatusCode.OK;
}
This works fine without ValidateAntiForgeryToken
, but as soon as I go ...
[HttpDelete("/delete/{resource}"), ValidateAntiForgeryToken]
๐ฅ I get a 400 Bad Request.
Both the button and the script are within a <form>
and I can see the antiforgery token going out on the DELETE in request headers (via Fiddler) ...
Cookie: X-XSRF-COOKIE=CfDJ8Ag6EezFPexKq5ZuFJ4kc............;
What am I missing?
I have attempted to follow the sample source provided here. I'm currently using "Microsoft.AspNet.Antiforgery": "1.0.0-rc1-final"
. The sample source code seems to work "ok" but I really want something more like the current version here.
I need the ability to use the Cookie approach for my Angular2 application. How can I achieve? Here is the middleware that I'm attempting to use:
public class AntiforgeryMiddleware
{
private readonly IAntiforgery _antiforgery;
private readonly AntiforgeryOptions _options;
private readonly RequestDelegate _next;
public AntiforgeryMiddleware(RequestDelegate next,
IAntiforgery antiforgery,
IOptions<AntiforgeryOptions> options)
{
_next = next;
_antiforgery = antiforgery;
_options = options.Value;
}
public async Task Invoke(HttpContext context)
{
if (string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase))
{
var tokenSet = _antiforgery.GetAndStoreTokens(context);
if (tokenSet.CookieToken != null)
{
context.Response.Cookies.Append(_options.CookieName, tokenSet.CookieToken, new CookieOptions {HttpOnly = false});
}
}
else if (string.Equals("POST", context.Request.Method, StringComparison.OrdinalIgnoreCase))
{
// At this point the context.Request.Headers has my cookie token
// But if I were to invoke _antiforgery.GetTokens(context), it wouldn't have a cookie token!
await _antiforgery.ValidateRequestAsync(context);
}
await _next(context);
}
}
The odd thing is that in the context.Request.Headers
I have the cookie token that I'm expecting, however; the current Microsoft.AspNet.Antiforgery.DefaultAntiforgery.ValidateRequestAsync
function seems to expect both a cookie and a form token -- which I believe is incorrect. Please help...
As I know, CSRF is only problem for browsers with cookie based authentication (since cookies are sent in a cross site request).
Think that we added global AutoValidateAntiforgeryTokenAttribute
to protect out application. What if we want to use same controllers (API controllers) from a mobile application (or from postman for tests). In that case, we don't want to send antiforgery token in the cookie, because it's not a security problem for these clients, and it's hard to do it.
The problem is this code: https://github.com/aspnet/Antiforgery/blob/dev/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs#L160
It throws exception if antiforgery cookie is not sent. My suggestion is to assume the request valid if this cookie is not present. Because, a cross-site request can not prevent to send this cookie (and just send the auth cookie).
What do you think?
Hi
With .NET Core RC1 the following code to validate an antiforgery token worked. I can see that the api has changed in RC2
RC1 Working code
using Microsoft.AspNet.Antiforgery;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.Extensions.OptionsModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FortMembership.Filters
{
public class ValidateAntiForgeryHeaderToken : TypeFilterAttribute
{
public ValidateAntiForgeryHeaderToken() : base(typeof(ValidateAntiForgeryHeaderTokenImpl))
{
}
// see https://docs.asp.net/en/latest/mvc/controllers/filters.html
//
// If you have a simple filter that doesnโt require any arguments, but which has constructor dependencies that need to be filled by DI,
// you can inherit from TypeFilterAttribute, allowing you to use your own named attribute on classes and methods (instead of [TypeFilter(typeof(FilterType))]).
//
private class ValidateAntiForgeryHeaderTokenImpl : IAsyncAuthorizationFilter
{
private readonly IAntiforgery _antiforgery;
public readonly string verificationToken = "X-VerificationToken";
public readonly string antiforgeryCookieName;
public ValidateAntiForgeryHeaderTokenImpl(IAntiforgery antiforgery, IOptions<AntiforgeryOptions> antiforgeryOptions)
{
_antiforgery = antiforgery;
antiforgeryCookieName = antiforgeryOptions.Value.CookieName; // if not specified this is autogenerated by mvc
}
public Task OnAuthorizationAsync(AuthorizationContext context)
{
string headerToken = context.HttpContext.Request.Headers[verificationToken];
if (headerToken != null)
{
string antiForgeryCookieValue = context.HttpContext.Request.Cookies[antiforgeryCookieName];
_antiforgery.ValidateTokens(context.HttpContext, new AntiforgeryTokenSet(headerToken, antiForgeryCookieValue)); // throws on invalid
return Task.FromResult<object>(null);
}
return _antiforgery.ValidateRequestAsync(context.HttpContext);
}
}
}
}
Can you point me in the right direction with RC2 , I cannot see the API calls necessary to create a new tokenset and validate
return await _antiforgery.ValidateRequestAsync(context.HttpContext, /* new AntiforgeryTokenSet(headerToken, antiForgeryCookieValue */));
Thanks
Hi,
I'm using angular along with asp.net 5. I'm trying to store the cookie / form token so I can pass it into the controller on an ajax post. Everything is fine when in debug mode. When I go to the publish to IIS the cookie token is always blank.
Constructor (IAntiforgery antiforgery)
{
}
Method var token = Antiforgery.GetAndStoreTokens(Context);
token.CookieToken is blank at this point.
What am I missing here? I don't see any bugs and I'm pretty sure you have unit test on this.
I'm using Beta 7.
This would let us get rid of the service locator antipattern...
-Microsoft.AspNetCore.Antiforgery\Internal\DefaultAntiforgery.cs:331:
var contextAccessor = services.GetRequiredService<IAntiforgeryContextAccessor>();
-Microsoft.AspNetCore.Antiforgery\Internal\DefaultAntiforgery.cs:441:
var contextAccessor = services.GetRequiredService<IAntiforgeryContextAccessor>();
Allow API user to Configure if the cookie generated is HttpOnly or not
Expected that because of the Architecture design, a developer using ValidateToken Configured for Angular Cookie and Header functionality, that the ValidationToken Cookie should be configured correctly.
Angular is prevented from reading the ValidationToken Cookie because it is set as HTTPOnly, which prevents angular calling endpoints secured with [ValidateToken] or [AutoValidateToken]
Documentation for AngularJS V1 CSRF CookieToHeader Architecture
Wikipedia CSRF Cookie to Header which states that by the architectural design of the CookieToHeader Architecture the ValidationToken cookie needs to be readable by JavaScript
Root of issue, ellipses for brevity
namespace Microsoft.AspNetCore.Antiforgery.Internal
{
public class DefaultAntiforgeryTokenStore : IAntiforgeryTokenStore
{
...
public void SaveCookieToken(HttpContext httpContext, string token)
{
...
options.HttpOnly = true; // This is hardcoded and cannot be changed
...
}
...
}
}
*Use this issue for feedback, questions and discussions related to aspnet/Announcements#156 *
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.
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.
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).
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.
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:
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 treated by the auth system as "not logged in". This might mean a challenge, login screen, or unauthorized response.
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.
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.
With the following commit, the path of the antiforgery's cookie token is set to always use the request's PathBase
. Consider exposing the cookie's options via the AntiforgeryOptions
to enable users to set it explicitly if they need to.
When a user is Logged in, and goes to Login Page while so. If he tries to login again you get Anti forgery Error.
I try to use filter and middle ware to intercept the "AntiforgeryValidationException", but failed. It always show blank page.
Guidance from @blowdart is to not use the angular double cookie support, but instead follow the pattern used in https://github.com/aspnet/Entropy/tree/dev/samples/Mvc.AjaxAntiforgeryAuth.Web.
XSRF-TOKEN is not added on localhost in request headers.
Set-up in Startup.cs:
public void ConfigureDevelopmentServices(IServiceCollection services)
{
services.AddAntiforgery(o => { o.HeaderName = "X-XSRF-TOKEN"; o.RequireSsl = false; });
ConfigureEnvironmentAgnosticServices(services);
}
Then in Configure method:
app.Use(next => context =>
{
if (
string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase))
{
var tokens = antiforgery.GetAndStoreTokens(context);
context.Items.Add("XSRF-TOKEN", tokens.RequestToken);
}
return next(context);
});
Antiforgery middleware:
public async Task Invoke(HttpContext context)
{
if (string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
{
await _antiforgery.ValidateRequestAsync(context);
}
await _next.Invoke(context);
}
Error:
AntiforgeryValidationException: The required antiforgery header value "X-XSRF-TOKEN" is not present.
XSRF type is not added in headers in localhost, so it is impossible to test it on localhost. Works on remote servers though.
Can't seem to figure out this.
Related to #66
We don't want to ship this in an RC2 release because it's not going to be our long-term solution.
I've tried with both ...
services.AddAntiforgery(options =>
{
options.CookieName = "MY_X-XSRF-COOKIE";
options.HeaderName = "MY_X-XSRF-TOKEN";
});
... and ...
services.Configure<AntiforgeryOptions>(options =>
{
options.CookieName = "MY_X-XSRF-COOKIE";
options.HeaderName = "MY_X-XSRF-TOKEN";
});
... but I'm only getting ...
.AspNetCore.Antiforgery.uZGDUqdnfBA=...................................;
[EDIT] I looked at the repo tests, and this looks correct. I feel that I'm missing something simple here.
I've been trying to get this to work for a while and find few examples. Actually this quite elegant method of antiforgery prompted me to upgrade from RC1 to RC2, which was a bit painful but everything is working now, except this.
Here is my code that is based on your angular.js example, I only have problem with the last part app.Map() that is causing the request to stop even if its a "GET" request - an empty response comes back. Any ideas?
app.Use(next => context =>
{
if (
string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(context.Request.Path.Value, "/index.html", StringComparison.OrdinalIgnoreCase))
{
// We can send the request token as a JavaScript-readable cookie, and Angular will use it by default.
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });
}
return next(context);
});
// Configure the HTTP request pipeline.
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseSession();
// Add MVC to the request pipeline.
app.Map("/api", a => a.Run(async context =>
{
if (string.Equals("POST", context.Request.Method, StringComparison.OrdinalIgnoreCase))
{
// This will throw if the token is invalid.
await antiforgery.ValidateRequestAsync(context);
}
}));
app.UseMvc();
When attempting to manually generate and consume time-limited tokens (#36 (comment)), I'm using TryValidateTokenSet
directly, but when either of the tokens are set to null
(as I have setup in my own Deserialize
method when DP says that the token is expired ... I just return null
for the token), the TryValidateTokenSet
method doesn't flow the result and message well for me at
Here's how null tokens are handled now. They throw ...
if (cookieToken == null)
{
throw new ArgumentNullException(
nameof(cookieToken),
Resources.Antiforgery_CookieToken_MustBeProvided_Generic);
}
if (requestToken == null)
{
throw new ArgumentNullException(
nameof(requestToken),
Resources.Antiforgery_RequestToken_MustBeProvided_Generic);
}
It looks like it wasn't a prob for the original specification for antiforgery, because the only null tokens are those that aren't part of the request in the first place. I see the tests very early on for the cookie and either header or body request token being null
(missing from the request). If missing, I see they get handled prior to the validation attempt. I guess the original thinking was that in TryValidateTokenSet
null
would never be a "good" value to get back out of deserialization. However, that's exactly the case here.
It's better for me to return a null token from deserialization when the DP throws claiming that the token is expired. I can't very well return an actual token. ๐ Since for me, a null token is fine out of deserialization, I'd like to just have TryValidateTokenSet
flow it back to the caller cleanly just like the rest of the validation failures there ...
if (cookieToken == null)
{
message = Resources.Antiforgery_CookieToken_MustBeProvided_Generic;
return false;
}
if (requestToken == null)
{
message = Resources.Antiforgery_RequestToken_MustBeProvided_Generic;
return false;
}
I realize I can replace the method, but it would make it easier to consume the result of this OOB method if it were built-in. I would like to just do this ...
if (!tokenGenerator.TryValidateTokenSet(
HttpContext,
deserializedCookieToken,
deserializedRequestToken,
out message))
{
// Log message here
return HttpStatusCode.BadRequest;
}
return HttpStatusCode.OK;
but if I don't replace this method, then I'm stuck having to do this ...
try
{
if (!tokenGenerator.TryValidateTokenSet(
HttpContext,
deserializedCookieToken,
deserializedRequestToken,
out message))
{
// Log message here
return HttpStatusCode.BadRequest;
}
}
catch (System.Exception ex)
{
// Log exception here (for me, this will prob be an expired token out of DP)
return HttpStatusCode.BadRequest;
}
return HttpStatusCode.OK;
Hi
In my single-page application using ajax requests I need to sign-in user using ajax (with antiforgery token provided by GetAndStoreTokens()) - all nice and well, but after the sign-in subsequent requests fail with error: "The provided antiforgery token was meant for a different claims-based user than the current user."
So of course I tried to return new token (using GetAndStoreTokens()) at the end of sign-in request, but it still doesn't work. My understanding of the source code is that Antiforgery service is not updating cookies if they are already set, regardless if they are still valid or not. How can I update the antiforgery tokens after the user signs in?
Microsoft.Extensions.DependencyInjection.ServiceCollectionExtensions
=> Microsoft.Extensions.DependencyInjection.AntiforgeryServiceCollectionExtensions
Associated announcement: aspnet/Announcements#187
When I ran my app with debugger attached on Linux, I always hit fault on accessing invalid address. It turned out due to missing antiforgery cookie in the client request. So basically the test client faked requests and avoided using antiforgery token. The server code handling this is not checking whether this cookie exists or not before handling to deserializer.
Process 42821 stopped
* thread #15: tid = 42953, 0x00007fff7e0db40e, name = 'StarterMvc', stop reason = invalid address (fault address: 0x8)
frame #0: 0x00007fff7e0db40e
-> 0x7fff7e0db40e: movl 0x8(%rbx), %r14d
0x7fff7e0db412: movl %r14d, %edi
0x7fff7e0db415: callq 0x7fff7e0c5c90
0x7fff7e0db41a: movl %eax, %esi
(lldb) bt
* thread #15: tid = 42953, 0x00007fff7e0db40e, name = 'StarterMvc', stop reason = invalid address (fault address: 0x8)
* frame #0: 0x00007fff7e0db40e
frame #1: 0x00007fff7e0daeab
frame #2: 0x00007fff7e0dad84
frame #3: 0x00007fff7e0dab6e
frame #4: 0x00007fff7e0da86e
frame #5: 0x00007fff7e0da383
โฆ
frame #90: 0x00007fff7c9d3215
frame #91: 0x00007ffff6420fa7 libcoreclr.so`CallDescrWorkerInternal + 124
frame #92: 0x00007ffff633c09e libcoreclr.so`MethodDescCallSite::CallTargetWorker(unsigned long const*) + 862
frame #93: 0x00007ffff6538a0a libcoreclr.so`QueueUserWorkItemManagedCallback(void*) + 186
frame #94: 0x00007ffff630ff8e libcoreclr.so`ManagedThreadBase_DispatchOuter(ManagedThreadCallState*) + 430
frame #95: 0x00007ffff6310736 libcoreclr.so`ManagedThreadBase::ThreadPool(ADID, void (*)(void*), void*) + 70
frame #96: 0x00007ffff651a974 libcoreclr.so`ManagedPerAppDomainTPCount::DispatchWorkItem(bool*, bool*) + 292
frame #97: 0x00007ffff632e8ec libcoreclr.so`ThreadpoolMgr::WorkerThreadStart(void*) + 1228
frame #98: 0x00007ffff67d96c9 libcoreclr.so`CorUnix::CPalThread::ThreadEntry(pvParam=0x0000000000832cf0) + 297 at thread.cpp:1641
frame #99: 0x00007ffff79c0182 libpthread.so.0`start_thread + 194
frame #100: 0x00007ffff6ecd47d libc.so.6`clone + 109
The missing stacks are managed stack:
(lldb) clrstack
OS Thread Id: 0xa7c9 (15)
Child SP IP Call Site
00007FFF5FFFA6E0 00007FFF7E0DB40E Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(System.String)
00007FFF5FFFA730 00007FFF7E0DAEAB Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetCookieTokenDoesNotThrow(Microsoft.AspNetCore.Http.HttpContext)
00007FFF5FFFA760 00007FFF7E0DAD84 Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetCookieTokens(Microsoft.AspNetCore.Http.HttpContext)
00007FFF5FFFA790 00007FFF7E0DAB6E Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetTokensInternal(Microsoft.AspNetCore.Http.HttpContext)
00007FFF5FFFA7C0 00007FFF7E0DA86E Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetAndStoreTokens(Microsoft.AspNetCore.Http.HttpContext)
00007FFF5FFFA7F0 00007FFF7E0DA383 Microsoft.AspNetCore.Mvc.ViewFeatures.AntiforgeryExtensions.GetHtml(Microsoft.AspNetCore.Antiforgery.IAntiforgery,
In the code:
private AntiforgeryToken GetCookieTokenDoesNotThrow(HttpContext httpContext)
{
try
{
var serializedToken = _tokenStore.GetCookieToken(httpContext);
var token = _tokenSerializer.Deserialize(serializedToken);
return token;
}
catch
{
// ignore failures since we'll just generate a new token
return null;
}
โฆ
public AntiforgeryToken Deserialize(string serializedToken)
{
var serializationContext = _pool.Get();
Exception innerException = null;
try
{
var count = serializedToken.Length;
Although this exception would be captured and ignored, it incurs extra cost, and could be easily avoided by checking if the searializedToken is null.
Downloading KoreBuild from https://github.com/aspnet/KoreBuild/archive/dev.zip
Building /Users/dfowler/dev/Universe/Antiforgery
dotnet_install: Preparing to install .NET Tools from 'beta' channel to '/Users/dfowler/.dotnet'
dotnet_install: You already have the version 1.0.0.001718.
log : Restoring packages for /Users/dfowler/dev/Universe/Antiforgery/.build/project.json...
log : Installing xunit.abstractions 2.0.0.
log : Installing xunit.extensibility.execution 2.1.0.
log : Installing xunit.extensibility.core 2.1.0.
log : Installing NuGetPackageVerifier 1.0.1-rc2-15044.
log : Installing xunit.core 2.1.0.
log : Installing xunit.runner.console 2.1.0.
log : Installing Sake 0.2.2.
log : .build/project.json
log : Restore completed in 2129ms.
info: Run target: default
info: Run target: pre-clean
info: Run target: target-dir-clean
info: Run target: clean
info: Run target: post-clean
info: Run target: validate
info: Run target: restore-npm-modules
info: Testing for command: node --version
warn: command exception: System.ComponentModel.Win32Exception: ApplicationName='node', CommandLine='--version', CurrentDirectory='', Native error= Cannot find the specified file
at System.Diagnostics.Process.Start_noshell (System.Diagnostics.ProcessStartInfo startInfo, System.Diagnostics.Process process) [0x00000] in <filename unknown>:0
at System.Diagnostics.Process.Start_common (System.Diagnostics.ProcessStartInfo startInfo, System.Diagnostics.Process process) [0x00000] in <filename unknown>:0
at System.Diagnostics.Process.Start (System.Diagnostics.ProcessStartInfo startInfo) [0x00000] in <filename unknown>:0
at View40283d0c75a2426fb51406ae3a1a1d15.TestCommand (System.String program, System.String commandline) [0x00000] in <filename unknown>:0
warn: command not found
info: Exec
info: program: npm
info: commandline: install --quiet --depth 0
info: workingdir: /Users/dfowler/dev/Universe/Antiforgery/samples/AntiforgerySample
fail: One or more errors occurred.
fail: Stack trace:
at System.Threading.Tasks.Task.ThrowIfExceptional (Boolean includeTaskCanceledExceptions) [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.Wait (Int32 millisecondsTimeout, CancellationToken cancellationToken) [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.Wait () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Parallel.ForWorker[Object] (Int32 fromInclusive, Int32 toExclusive, System.Threading.Tasks.ParallelOptions parallelOptions, System.Action`1 body, System.Action`2 bodyWithState, System.Func`4 bodyWithLocal, System.Func`1 localInit, System.Action`1 localFinally) [0x00000] in <filename unknown>:0
Davids-MacBook-Pro:Antiforgery dfowler$
I'm using Antiforgery for a site we're building for a large insurer, I just received the results of a security audit, the auditor insists the request token should be invalidated on each request. I cannot find a way to enforce new tokens for every request. Can someone tell me if this is possible and how? If its not possible would you consider adding it?
According to @blowdart and @lodejard the way we generate the UID for a ClaimsPrincipal
is wrong in antiforgery.
We should use the ClaimsIdentity.NameClaimType
of all authenticated identities to generate the UID rather than looking for a claim of type ClaimTypes.NameIdentifier
.
We need to also figure out the right thing to do (or if it's possible) when the user does not have a name.
Not sure if it should be here or in MVC, but this seems like the right place.
I'm playing around with getting this to work for API calls. I notice that when I don't deliver an anti forgery token, the request results in a 500. Maybe this is just me, but shouldn't this be a 400? The server shouldn't fail (and log a 500) simply because I (or any other third party) forgets to add this token (read: bad request).
Exception I get is:
An unhandled exception has occurred: The required antiforgery form field "__RequestVerificationToken" is not present.
System.InvalidOperationException: The required antiforgery form field "__RequestVerificationToken" is not present.
at Microsoft.AspNet.Antiforgery.DefaultAntiforgeryTokenStore.<GetRequestTokensAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Antiforgery.DefaultAntiforgery.<ValidateRequestAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAuthorizationFilterAsync>d__47.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAuthorizationFilterAsync>d__47.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAsync>d__44.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.<RouteAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Mvc.Routing.InnerAttributeRoute.<RouteAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Routing.RouteCollection.<RouteAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.IISPlatformHandler.IISPlatformHandlerMiddleware.<Invoke>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.Diagnostics.ExceptionHandlerMiddleware.<Invoke>d__6.MoveNext()
In previous version of ASP.NET during SPA application the idea of AntiForgey token was following:
@Html.AntiForgeryToken();
on the page__RequestVerificationToken
to the requestI don't really understand the authorization requirements (is there some good information source?) in ASP.NET 5 but looks like new behavior should be like this:
asp-anti-forgerytaghelper
__RequestVerificationToken
to the requestThe question is: how to write this new authorization requirement and remove standard one?
Could someone give some advice or point me on some example? Thanks
P.S. Looks like I need to create custome middleware and check if it's json to use my way or use standard await _antiforgery.ValidateRequestAsync(context);
But still not sure about it.
I was trying to follow the sample code provided for AntiForgery
There anti-forgery token is written to a cookie where AngularJS (Javascript) can read it and use it on every subsequent XHR requests.
I see that even when the same token is used more than once, It is considered to be a valid token and everything is just normal. When and how an issued token gets invalid?
If the token can be used more than once, how is it secure to use it with AngularJS (Javascript)?
What happens if malicious code get access to this token?
It seems that the tokens are stored in local machine, how to make it store in Redis or a distributed environment?
We'll be setting the Machine Key as usual for .NET 5 apps using Antiforgery in web farm scenarios, correct?
If so, this might be a feature request: Any interest in providing some control of the Machine Key somewhere in Startup.cs
(or does that already exist)? Continuing to use web.config
sucks, and IIS settings are inconvenient.
Besides the Machine Key, are there any other gotchas we should be aware of with Antiforgery in a web farm scenario?
It would be nice that ValidateAntiForgeryTokenAttribute (or DefaultAntiforgeryTokenStore) search token in headers too, not only in values posteds from forms.
So we can easily apply CSRF protection in Ajax calls to REST services (angularjs or jquery apps).
When I use UseStatusCodePagesWithReExecute
and get a 404 is there any way I can know that the cause is that the validation of the antiforgery token failed?
I tried getting this information via Features
but it was no success:
[Route("~/Error/{code}")]
public IActionResult Error(string code /*400 when validation failed*/)
{
var itsNull1 = HttpContext.Features.Get<IAntiforgery>();
var itsNull2 = HttpContext.Features.Get<IAntiforgeryAdditionalDataProvider>();
var itsNull3 = HttpContext.Features.Get<IAntiforgeryFeature>();
var itsNull4 = HttpContext.Features.Get<AntiforgeryFeature>();
var itsNull5 = HttpContext.Features.Get<AntiforgeryValidationException>();
var status = Response.StatusCode; // 200 when validation failed
...
One thing I found is that normally the following is true inside the Error
action: code = Response.StatusCode.ToString()
. It's true for instance when I return a 400 StatusCodeResult myself from an action. Now when the Error
action is executed because the token validation failed then code
is "400"
and Response.StatusCode
is 200
for some reason.
Is it safe to assume that when code == "400" && Response.StatusCode == 200
Antiforgery is responsible?
Unable to resolve 'Microsoft.AspNetCore.Antiforgery (>= 1.0.0-rc3-21156)' for '.NETFramework,Version=v4.5.2'.
Hi Everyone
I have an ASP.NET Core backend with some Web APIs, and an AngularJS client on separate subdomains (Actually on localhost with different ports), and I can't seem to get Antiforgery to work.
I get 400 Bad request response on APIs protected with [ValidateAntiForgeryToken], this is my backend code :
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
...
app.Use(next => context => {
tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });
return next(context);
});
First problem i've got is that the cookie is not set on my AngularJS app, i've resolved it by setting WithCredentials to true : $httpProvider.defaults.withCredentials = true;
The second one is that the X-XSRF-TOKEN header is not set automatically by AngularJS, and i've solved it by setting an interceptor : config.headers['X-XSRF-TOKEN'] = $cookies.get('XSRF-TOKEN');
Now I can receive the token and send it with my $http requests, I don't understand why API calls are rejected ! Is it related that the applications are not on the same port ?
Thanks in advance :)
I'm working on a system that has FIPS-compliant enabled and am wondering is there a way to change the Antiforgery defaults to make it compliant. If someone could provide some direction or feedback that would appreciated.
Thanks
See https://github.com/aspnet/Security/issues/773
Only apply it if AntiforgeryOptions.RequreSsl is true.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.