validateantiforgerytoken que asp.net-mvc asp.net-web-api antiforgerytoken

asp.net mvc - que - Web API y ValidateAntiForgeryToken



validateantiforgerytoken ajax (5)

Complementando el código anterior FilterAttribute

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] public sealed class ValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter { public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) { try { string cookieToken = ""; string formToken = ""; IEnumerable<string> tokenHeaders; if (actionContext.Request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders)) { string[] tokens = tokenHeaders.First().Split('':''); if (tokens.Length == 2) { cookieToken = tokens[0].Trim(); formToken = tokens[1].Trim(); } } AntiForgery.Validate(cookieToken, formToken); } catch (System.Web.Mvc.HttpAntiForgeryException e) { actionContext.Response = new HttpResponseMessage { StatusCode = HttpStatusCode.Forbidden, RequestMessage = actionContext.ControllerContext.Request }; return FromResult(actionContext.Response); } return continuation(); } private Task<HttpResponseMessage> FromResult(HttpResponseMessage result) { var source = new TaskCompletionSource<HttpResponseMessage>(); source.SetResult(result); return source.Task; }

Función Html usando Razor

@functions{ public string TokenHeaderValue() { string cookieToken, formToken; AntiForgery.GetTokens(null, out cookieToken, out formToken); return cookieToken + ":" + formToken; } }

Usando Angular

return $http({ method: ''POST'', url: ''@Url.Content("~/api/invite/")'', data: {}, headers: { ''RequestVerificationToken'': ''@TokenHeaderValue()'' } });

Tenemos algunos servicios web de MVC que se llaman estilo AJAX de las páginas web. Estos servicios hacen uso del atributo ValidateAntiForgeryToken para ayudar a evitar falsificaciones de solicitudes.

Estamos buscando migrar estos servicios a la API web, pero parece que no hay una funcionalidad equivalente anti-falsificación.

¿Me estoy perdiendo de algo? ¿Existe un enfoque diferente para abordar las falsificaciones de solicitudes con la API web?


Después de pensar en esto un poco más, es una mala idea mezclar las cookies y los tokens de formulario, ya que anula todo el propósito del token anti falsificación. Es mejor mantener la parte de la cookie como una cookie al mover la parte del formulario a un encabezado de autenticación, por lo tanto, esta nueva respuesta (una vez más como AuthorizeAttribute).

using System; using System.Linq; using System.Net.Http; using System.Web; using System.Web.Helpers; using System.Web.Http; using System.Web.Http.Controllers; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class ApiValidateAntiForgeryToken : AuthorizeAttribute { public const string HeaderName = "X-RequestVerificationToken"; private static string CookieName => AntiForgeryConfig.CookieName; public static string GenerateAntiForgeryTokenForHeader(HttpContext httpContext) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } // check that if the cookie is set to require ssl then we must be using it if (AntiForgeryConfig.RequireSsl && !httpContext.Request.IsSecureConnection) { throw new InvalidOperationException("Cannot generate an Anti Forgery Token for a non secure context"); } // try to find the old cookie token string oldCookieToken = null; try { var token = httpContext.Request.Cookies[CookieName]; if (!string.IsNullOrEmpty(token?.Value)) { oldCookieToken = token.Value; } } catch { // do nothing } string cookieToken, formToken; AntiForgery.GetTokens(oldCookieToken, out cookieToken, out formToken); // set the cookie on the response if we got a new one if (cookieToken != null) { var cookie = new HttpCookie(CookieName, cookieToken) { HttpOnly = true, }; // note: don''t set it directly since the default value is automatically populated from the <httpCookies> config element if (AntiForgeryConfig.RequireSsl) { cookie.Secure = AntiForgeryConfig.RequireSsl; } httpContext.Response.Cookies.Set(cookie); } return formToken; } protected override bool IsAuthorized(HttpActionContext actionContext) { if (HttpContext.Current == null) { // we need a context to be able to use AntiForgery return false; } var headers = actionContext.Request.Headers; var cookies = headers.GetCookies(); // check that if the cookie is set to require ssl then we must honor it if (AntiForgeryConfig.RequireSsl && !HttpContext.Current.Request.IsSecureConnection) { return false; } try { string cookieToken = cookies.Select(c => c[CookieName]).FirstOrDefault()?.Value?.Trim(); // this throws if the cookie does not exist string formToken = headers.GetValues(HeaderName).FirstOrDefault()?.Trim(); if (string.IsNullOrEmpty(cookieToken) || string.IsNullOrEmpty(formToken)) { return false; } AntiForgery.Validate(cookieToken, formToken); return base.IsAuthorized(actionContext); } catch { return false; } } }

A continuación, simplemente decore su controlador o métodos con [ApiValidateAntiForgeryToken]

Y agregue al archivo razor esto para generar su token para javascript:

<script> var antiForgeryToken = ''@ApiValidateAntiForgeryToken.GenerateAntiForgeryTokenForHeader(HttpContext.Current)''; // your code here that uses such token, basically setting it as a ''X-RequestVerificationToken'' header for any AJAX calls </script>


Este stephenwalther.com/archive/2013/03/05/… ayudó, puedes recuperar el token antifalsificación de la vista de afeitar y pasar el token como un encabezado:

var csrfToken = $("input[name=''__RequestVerificationToken'']").val(); $.ajax({ headers: { __RequestVerificationToken: csrfToken }, type: "POST", dataType: "json", contentType: ''application/json; charset=utf-8'', url: "/api/products", data: JSON.stringify({ name: "Milk", price: 2.33 }), statusCode: { 200: function () { alert("Success!"); } } });


La respuesta de Oswaldo pero implementada como una AutorizaciónAtributo

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class ApiValidateAntiForgeryToken : AuthorizeAttribute { public static string GenerateAntiForgeryTokenForHeader() { string cookieToken, formToken; AntiForgery.GetTokens(null, out cookieToken, out formToken); return cookieToken + ":" + formToken; } protected override bool IsAuthorized(HttpActionContext actionContext) { var headers = actionContext.Request.Headers; // we pass both the cookie and the form token into a single header field string headerToken = headers.Contains("__RequestVerificationToken") ? headers.GetValues("__RequestVerificationToken").FirstOrDefault() : null; if (headerToken == null) { return false; } string[] tokens = headerToken.Split('':''); if (tokens.Length != 2) { return false; } string cookieToken = tokens[0].Trim(); string formToken = tokens[1].Trim(); try { AntiForgery.Validate(cookieToken, formToken); } catch { return false; } return base.IsAuthorized(actionContext); } }

Puede decorar su controlador o métodos con [ApiValidateAntiForgeryToken] y luego pasar RequestVerificationToken: "@ ApiValidateAntiForgeryToken.GenerateAntiForgeryTokenForHeader ()" como encabezado para el método en su código razor javascript.


Usted podría implementar dicho atributo de autorización:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] public sealed class ValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter { public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) { try { AntiForgery.Validate(); } catch { actionContext.Response = new HttpResponseMessage { StatusCode = HttpStatusCode.Forbidden, RequestMessage = actionContext.ControllerContext.Request }; return FromResult(actionContext.Response); } return continuation(); } private Task<HttpResponseMessage> FromResult(HttpResponseMessage result) { var source = new TaskCompletionSource<HttpResponseMessage>(); source.SetResult(result); return source.Task; } }

y decora tus acciones de API con él:

[ValidateAntiForgeryToken] public HttpResponseMessage Post() { // some work return Request.CreateResponse(HttpStatusCode.Accepted); }