Llamadas jQuery Ajax y el Html.AntiForgeryToken ()

207

He implementado en mi aplicación la mitigación de los ataques CSRF siguiendo las informaciones que he leído en alguna publicación de blog en Internet. En particular, estas publicaciones han sido el motor de mi implementación

Básicamente, esos artículos y recomendaciones dicen que para evitar el ataque CSRF cualquiera debería implementar el siguiente código:

1) Agregue el [ValidateAntiForgeryToken]en cada acción que acepte el verbo Http POST

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SomeAction( SomeModel model ) {
}

2) Agregue el <%= Html.AntiForgeryToken() %>ayudante dentro de los formularios que envían datos al servidor

<div style="text-align:right; padding: 8px;">
    <%= Html.AntiForgeryToken() %>
    <input type="submit" id="btnSave" value="Save" />
</div>

De todos modos, en algunas partes de mi aplicación, estoy haciendo Ajax POST con jQuery al servidor sin tener ningún formulario. Esto sucede, por ejemplo, cuando dejo que el usuario haga clic en una imagen para realizar una acción específica.

Supongamos que tengo una tabla con una lista de actividades. Tengo una imagen en una columna de la tabla que dice "Marcar actividad como completada" y cuando el usuario hace clic en esa actividad, estoy haciendo la POST de Ajax como en la siguiente muestra:

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {},
        success: function (response) {
            // ....
        }
    });
});

¿Cómo puedo usar el <%= Html.AntiForgeryToken() %>en estos casos? ¿Debo incluir la llamada de ayuda dentro del parámetro de datos de la llamada Ajax?

Perdón por la larga publicación y muchas gracias por ayudar

EDITAR :

Según la respuesta de jayrdub , he usado de la siguiente manera

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {
            AddAntiForgeryToken({}),
            id: parseInt($(this).attr("title"))
        },
        success: function (response) {
            // ....
        }
    });
});
Lorenzo
fuente
El enlace de David Hayden ahora es 404, parece que ha migrado su blog a un nuevo CMS, pero no migró todo el contenido anterior.

Respuestas:

252

Yo uso una simple función js como esta

AddAntiForgeryToken = function(data) {
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
    return data;
};

Dado que cada formulario en una página tendrá el mismo valor para el token, simplemente coloque algo como esto en su página maestra superior

<%-- used for ajax in AddAntiForgeryToken() --%>
<form id="__AjaxAntiForgeryForm" action="#" method="post"><%= Html.AntiForgeryToken()%></form>  

Luego, en su llamada ajax do (editado para que coincida con su segundo ejemplo)

$.ajax({
    type: "post",
    dataType: "html",
    url: $(this).attr("rel"),
    data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
    success: function (response) {
        // ....
    }
});
JeremyWeir
fuente
66
Agradable, me gusta la encapsulación de la búsqueda de tokens.
jball el
2
@Lorenzo, ponga sus datos personalizados dentro de la llamada para AddAntiForgeryToken, así:data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
jball
3
¿Qué tan mala idea sería usar ajaxSendo anular ajaxpara aumentar siempre datacon el token antifalsificación? Tal vez agregue algún control para asegurarse de que urlesté destinado a su servidor.
ta.speot.is
1
Tenga cuidado si usa caché de salida.
Barbaros Alp
1
@SouhaiebBesbes, el token de validación debe ser el mismo para un usuario en todas las páginas (funciona junto con una cookie que se establece y permanece igual). Por lo tanto, no importa si hay varias solicitudes por página, será lo mismo si la página base se vuelve a cargar de todos modos.
JeremyWeir
29

Me gusta la solución proporcionada por 360Airwalk, pero puede mejorarse un poco.

El primer problema es que si realiza $.post()con datos vacíos, jQuery no agrega un Content-Typeencabezado, y en este caso ASP.NET MVC no puede recibir y verificar el token. Por lo tanto, debe asegurarse de que el encabezado siempre esté allí.

Otra mejora es el soporte de todos los verbos HTTP con contenido : POST, PUT, DELETE, etc. Aunque puede usar solo POSTs en su aplicación, es mejor tener una solución genérica y verificar que todos los datos que reciba con cualquier verbo tengan una falsificación simbólico.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $(document).ajaxSend(function (event, request, opt) {
        if (opt.hasContent && securityToken) {   // handle all verbs with content
            var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            opt.data = opt.data ? [opt.data, tokenParam].join("&") : tokenParam;
            // ensure Content-Type header is present!
            if (opt.contentType !== false || event.contentType) {
                request.setRequestHeader( "Content-Type", opt.contentType);
            }
        }
    });
});
Bronx
fuente
1
+1 tienes razón, no he pensado en el problema de la llamada vacía. Gracias por el aporte. tenías razón acerca de que todavía no usamos delete / put en nuestro proyecto.
360Airwalk
2
+1 por salvarme de tener que agregar la función a todas las llamadas jQuery.Ajax
Dragos Durlut
2
+1 Solo como una nota para la posteridad, la documentación de jQuery para los .ajaxSend()estados "A partir de jQuery 1.8, el método .ajaxSend () solo debe adjuntarse al documento". api.jquery.com/ajaxsend
RJ Cuthbertson
1
@Bronx ¿De dónde optionsviene el que figura en la ifdeclaración final ? Gracias.
hvaughan3
Tenga cuidado al usar esto si tiene varios formularios en una página. Deberá establecer el valor en beforeSend con una llamada de selector más específica en lugar de para el documento.
Dan
22

Sé que hay muchas otras respuestas, pero este artículo es agradable y conciso y te obliga a revisar todos tus HttpPosts, no solo algunos de ellos:

http://richiban.wordpress.com/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/

Utiliza encabezados HTTP en lugar de intentar modificar la colección de formularios.

Servidor

//make sure to add this to your global action filters
[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value 
                    : null;

                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

Cliente

var token = $('[name=__RequestVerificationToken]').val();
var headers = {};
headers["__RequestVerificationToken"] = token;

$.ajax({
    type: 'POST',
    url: '/Home/Ajax',
    cache: false,
    headers: headers,
    contentType: 'application/json; charset=utf-8',
    data: { title: "This is my title", contents: "These are my contents" },
    success: function () {
        ...
    },
    error: function () {
        ...
    }
});
viggity
fuente
44
El atributo del artículo que vinculó también combinado con la respuesta de Bronx es la solución DRY definitiva para este problema.
TugboatCaptain
2
Gran hallazgo. Edité su respuesta para incluir los fragmentos de código para que la respuesta sea independiente, pero espero que la gente también lea el resto del artículo. Esto parece ser una solución muy limpia.
Tim Medora
gracias Tim, es una excelente idea, es frustrante cuando un enlace se corta y la respuesta deja de tener valor. Empecé a hacer esto en todas mis nuevas respuestas.
viggity
¿Es este MVC, WebAPI o .NetCore? No puedo obtener los espacios de nombres correctos para WebAPI 5
Myster
20

Me siento como un nigromante avanzado aquí, pero esto sigue siendo un problema 4 años después en MVC5.

Para manejar correctamente las solicitudes de ajax, el token antifalsificación debe pasarse al servidor en las llamadas de ajax. Integrarlo en sus datos y modelos de publicación es desordenado e innecesario. Agregar el token como un encabezado personalizado es limpio y reutilizable, y puede configurarlo para que no tenga que acordarse de hacerlo cada vez.

Hay una excepción: el discreto ajax no necesita un tratamiento especial para las llamadas de ajax. El token se pasa como de costumbre en el campo de entrada oculto normal. Exactamente lo mismo que un POST regular.

_Layout.cshtml

En _layout.cshtml tengo este bloque de JavaScript. No escribe el token en el DOM, sino que usa jQuery para extraerlo del literal de entrada oculto que genera el MVC Helper. La cadena mágica que es el nombre del encabezado se define como una constante en la clase de atributo.

<script type="text/javascript">
    $(document).ready(function () {
        var isAbsoluteURI = new RegExp('^(?:[a-z]+:)?//', 'i');
        //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative

        $.ajaxSetup({
            beforeSend: function (xhr) {
                if (!isAbsoluteURI.test(this.url)) {
                    //only add header to relative URLs
                    xhr.setRequestHeader(
                       '@.ValidateAntiForgeryTokenOnAllPosts.HTTP_HEADER_NAME', 
                       $('@Html.AntiForgeryToken()').val()
                    );
                }
            }
        });
    });
</script>

Tenga en cuenta el uso de comillas simples en la función beforeSend: el elemento de entrada que se representa utiliza comillas dobles que romperían el literal de JavaScript.

JavaScript del cliente

Cuando esto se ejecuta, se llama a la función beforeSend anterior y AntiForgeryToken se agrega automáticamente a los encabezados de solicitud.

$.ajax({
  type: "POST",
  url: "CSRFProtectedMethod",
  dataType: "json",
  contentType: "application/json; charset=utf-8",
  success: function (data) {
    //victory
  }
});

Biblioteca del servidor

Se requiere un atributo personalizado para procesar el token no estándar. Esto se basa en la solución de @ viggity, pero maneja el ajax discreto correctamente. Este código puede guardarse en su biblioteca común

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public const string HTTP_HEADER_NAME = "x-RequestVerificationToken";

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {

            var headerTokenValue = request.Headers[HTTP_HEADER_NAME];

            // Ajax POSTs using jquery have a header set that defines the token.
            // However using unobtrusive ajax the token is still submitted normally in the form.
            // if the header is present then use it, else fall back to processing the form like normal
            if (headerTokenValue != null)
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value
                    : null;

                AntiForgery.Validate(cookieValue, headerTokenValue);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

Servidor / Controlador

Ahora solo aplica el atributo a su Acción. Aún mejor, puede aplicar el atributo a su controlador y todas las solicitudes serán validadas.

[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
  return Json(true, JsonRequestBehavior.DenyGet);
}
Will D
fuente
Solución perfecta, mucho más centralizada. Gracias
David Freire
¿Puede explicar con más detalle por qué solo desea agregar el encabezado para las URL relativas? Eso pasó por mi cabeza. Gran solución!
MattM
relativa asegura que el encabezado solo se establezca en solicitudes que regresan a su propio servidor, ya que la configuración de ajax cubre todas las solicitudes realizadas con jquery, no queremos que el token se envíe en solicitudes jsonp o CORS. Esto también puede ser cierto para las URL absolutas, pero se garantiza que las relativas sean del mismo dominio.
Will D
1
@WillD Me gustó su solución, pero me vi obligado a modificarla un poco. Debido a que elige $.ajaxSetupdefinir un beforesendcontrolador de eventos general , puede suceder que lo sobrescriba. Encontré otra solución donde puede agregar un segundo controlador que también se llamará. Funciona bien y no interrumpe su implementación.
Viper
¿Alguien tiene una versión ASP.net 5 del cliente para validar el atributo AntiForgery? ¡Esta versión no se compila en la última versión!
Rob McCabe
19

No usar Html.AntiForgeryToken . En su lugar, use AntiForgery.GetTokens y AntiForgery.Validate de la API web como se describe en Prevención de ataques de falsificación de solicitudes entre sitios (CSRF) en la aplicación ASP.NET MVC .

Edward Brey
fuente
Para los métodos de acción del controlador que vinculan un tipo de modelo de servidor al AJAX JSON publicado, es necesario tener el tipo de contenido como "aplicación / json" para utilizar el enlazador de modelo adecuado. Desafortunadamente, esto impide el uso de datos de formulario, requeridos por el atributo [ValidateAntiForgeryToken], por lo que su método es la única forma que pude encontrar para que funcione. Mi única pregunta es, ¿sigue funcionando en una granja de servidores web o en varias instancias de roles web de Azure? ¿@Edward, o alguien más sabe si esto es un problema?
Richard B
@ Edward Brey ¿Puedes explicarnos por qué no deberíamos usarlo?
Odys
44
@Odys: No hay nada intrínsecamente incorrecto con Html.AntiForgeryToken, pero tiene inconvenientes: requiere un formulario, requiere jQuery y asume detalles de implementación de Html.AntiForgeryToken indocumentados. Aún así, está bien en muchos contextos. Mi afirmación "No use Html.AntiForgeryToken" probablemente salga demasiado fuerte. Mi significado es que no está destinado a ser utilizado con API web, mientras que el AntiForgery.GetTokens es más flexible.
Edward Brey
¡Gracias! Tuve que cambiarlo un poco para que funcione para un controlador MVC5, pero esta fue la solución
jao
3
Ciertamente no requiere un formulario. Solo necesita analizar el DOM por su nombre. Utilizando jquery, puedo agregarlo dentro de mi objeto de datos a través de los datos {__RequestVerificationToken: $ ("input [name = __ RequestVerificationToken]"). Val ()}
Anthony Mason
16

Estaba implementando este problema real en mi proyecto actual. Lo hice para todos los POST ajax que necesitaban un usuario autenticado.

En primer lugar, decidí conectar mis llamadas de jquery ajax para no repetirme con demasiada frecuencia. Este fragmento de JavaScript garantiza que todas las llamadas ajax (posteriores) agregarán mi token de validación de solicitud a la solicitud. Nota: el nombre .__RequestVerificationToken es utilizado por .Net framework para que pueda utilizar las características estándar de Anti-CSRF como se muestra a continuación.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});

En sus Vistas donde necesita que el token esté disponible para el javascript anterior, simplemente use el HTML-Helper común. Básicamente, puede agregar este código cuando lo desee. Lo puse dentro de una declaración if (Request.IsAuthenticated):

@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller

En su controlador simplemente use el mecanismo estándar ASP.Net MVC Anti-CSRF. Lo hice así (aunque en realidad usé Salt).

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
    // do something
    return Json(true);
}

Con Firebug o una herramienta similar, puede ver fácilmente cómo sus solicitudes POST ahora tienen un parámetro __RequestVerificationToken adjunto.

360Airwalk
fuente
15

Creo que todo lo que tiene que hacer es asegurarse de que la entrada "__RequestVerificationToken" esté incluida en la solicitud POST. La otra mitad de la información (es decir, el token en la cookie del usuario) ya se envía automáticamente con una solicitud POST de AJAX.

P.ej,

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: { 
            "__RequestVerificationToken":
            $("input[name=__RequestVerificationToken]").val() 
        },
        success: function (response) {
            // ....
        }
    });
});
jball
fuente
1
Después de muchas horas experimentando con la publicación de jQuery AJAX desde una página de MVC (Razor), esta fue la respuesta más simple de todo lo que funcionó para mí. Simplemente incluya sus propios campos de datos (o el modelo de vista, supongo) después del token como una nueva pieza de datos (pero dentro del objeto de datos original).
Ralph Bacon
¿Cómo implementaría esto si la función AJAX estuviera en una página .html y no en una página Razor?
Bob the Builder
Si su página html no tiene un servidor suministrado AntiForgeryToken, de todos modos es discutible. Si lo hace (no estoy seguro de cómo obtendrá uno en ese caso, pero suponiendo que lo sea), entonces lo anterior funcionaría bien. Si está intentando crear una página web sencilla que publicará una solicitud en un servidor que espera dicho token, y el servidor no generó dicha página, entonces no tiene suerte. Ese es esencialmente el punto de AntiForgeryToken ...
jball
6

También puedes hacer esto:

$("a.markAsDone").click(function (event) {
    event.preventDefault();

    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: $('<form>@Html.AntiForgeryToken()</form>').serialize(),
        success: function (response) {
        // ....
        }
    });
});

Esto está usando Razor, pero si está usando la WebFormssintaxis, también puede usar <%= %>etiquetas

Leonardo Garcia Crespo
fuente
4

Además de mi comentario en contra de la respuesta de @ JBall que me ayudó en el camino, esta es la respuesta final que funciona para mí. Estoy usando MVC y Razor y estoy enviando un formulario usando jQuery AJAX para poder actualizar una vista parcial con algunos resultados nuevos y no quería hacer una devolución completa (y un parpadeo de página).

Añade el @Html.AntiForgeryToken() interior del formulario como de costumbre.

Mi código de botón de envío AJAX (es decir, un evento onclick) es:

//User clicks the SUBMIT button
$("#btnSubmit").click(function (event) {

//prevent this button submitting the form as we will do that via AJAX
event.preventDefault();

//Validate the form first
if (!$('#searchForm').validate().form()) {
    alert("Please correct the errors");
    return false;
}

//Get the entire form's data - including the antiforgerytoken
var allFormData = $("#searchForm").serialize();

// The actual POST can now take place with a validated form
$.ajax({
    type: "POST",
    async: false,
    url: "/Home/SearchAjax",
    data: allFormData,
    dataType: "html",
    success: function (data) {
        $('#gridView').html(data);
        $('#TestGrid').jqGrid('setGridParam', { url: '@Url.Action("GetDetails", "Home", Model)', datatype: "json", page: 1 }).trigger('reloadGrid');
    }
});

He dejado la acción "éxito", ya que muestra cómo se está actualizando la vista parcial que contiene un MvcJqGrid y cómo se está actualizando (una cuadrícula jqGrid muy poderosa y este es un brillante envoltorio MVC).

Mi método de controlador se ve así:

    //Ajax SUBMIT method
    [ValidateAntiForgeryToken]
    public ActionResult SearchAjax(EstateOutlet_D model) 
    {
        return View("_Grid", model);
    }

Tengo que admitir que no soy fanático de PUBLICAR los datos de un formulario completo como un Modelo, pero si necesita hacerlo, esta es una forma de funcionar. MVC simplemente hace que el enlace de datos sea demasiado fácil, así que en lugar de someter 16 valores individuales (o una FormCollection de tipo débil), está bien, supongo. Si sabe mejor, avíseme, ya que quiero producir un código MVC C # robusto.

Ralph Bacon
fuente
4

Encontré esta idea muy inteligente en https://gist.github.com/scottrippey/3428114 por cada llamada $ .ajax modifica la solicitud y agrega el token.

// Setup CSRF safety for AJAX:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (options.type.toUpperCase() === "POST") {
        // We need to add the verificationToken to all POSTs
        var token = $("input[name^=__RequestVerificationToken]").first();
        if (!token.length) return;

        var tokenName = token.attr("name");

        // If the data is JSON, then we need to put the token in the QueryString:
        if (options.contentType.indexOf('application/json') === 0) {
            // Add the token to the URL, because we can't add it to the JSON data:
            options.url += ((options.url.indexOf("?") === -1) ? "?" : "&") + token.serialize();
        } else if (typeof options.data === 'string' && options.data.indexOf(tokenName) === -1) {
            // Append to the data string:
            options.data += (options.data ? "&" : "") + token.serialize();
        }
    }
});
masterlopau
fuente
Probé varias de las otras alternativas anteriores, esto es lo que me resolvió.
HostMyBus
Sin embargo, tuve que agregar if (options.contentType != false && options.contentType.indexOf('application/json') === 0) {para capturar llamadas Ajax que no habían especificado un tipo de contenido
HostMyBus
3

1.Defina la función para obtener el token del servidor

@function
{

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

2. Obtenga el token y configure el encabezado antes de enviarlo al servidor

var token = '@TokenHeaderValue()';    

       $http({
           method: "POST",
           url: './MainBackend/MessageDelete',
           data: dataSend,
           headers: {
               'RequestVerificationToken': token
           }
       }).success(function (data) {
           alert(data)
       });

3. Validación del servidor en HttpRequestBase en el método que maneja Publicar / obtener

        string cookieToken = "";
        string formToken = "";
        string[] tokens = Request.Headers["RequestVerificationToken"].Split(':');
            if (tokens.Length == 2)
            {
                cookieToken = tokens[0].Trim();
                formToken = tokens[1].Trim();
            }
        AntiForgery.Validate(cookieToken, formToken);
Tonman Neverwalk solo
fuente
1

Sé que ha pasado algún tiempo desde que se publicó esta pregunta, pero encontré un recurso realmente útil, que analiza el uso de AntiForgeryToken y hace que sea menos problemático de usar. También proporciona el complemento jquery para incluir fácilmente el token antiforgery en llamadas AJAX:

Recetas de solicitud antifalsificación para ASP.NET MVC y AJAX

No estoy contribuyendo mucho, pero tal vez alguien lo encuentre útil.

Slawek
fuente
¡Esa publicación es como una milla de largo! Estoy seguro de que es genial, pero tl; dr
BritishDeveloper
1
Lástima, porque cubre muy bien el tema. No solo le dice cómo usar la función, sino que le explica qué problema soluciona y le brinda contexto para comprender cómo usarla correctamente. Cuando se trata de seguridad, creo que la comprensión profunda es importante.
slawek
2
Si es importante, debe estar escrito de una manera que aliente a las personas a leerlo;)
Desarrollador británico
1

primer uso @ Html.AntiForgeryToken () en html

 $.ajax({
        url: "@Url.Action("SomeMethod", "SomeController")",
        type: 'POST',
        data: JSON.stringify(jsonObject),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        async: false,
        beforeSend: function (request) {
            request.setRequestHeader("RequestVerificationToken", $("[name='__RequestVerificationToken']").val());
        },
        success: function (msg) {
            alert(msg);
        }
Amir Reza
fuente
1

Aquí está la forma más fácil que he visto. Nota: Asegúrese de tener "@ Html.AntiForgeryToken ()" en su Vista

  $("a.markAsDone").click(function (event) {
        event.preventDefault();
        var sToken = document.getElementsByName("__RequestVerificationToken")[0].value;
        $.ajax({
            url: $(this).attr("rel"),
            type: "POST",
            contentType: "application/x-www-form-urlencoded",
            data: { '__RequestVerificationToken': sToken, 'id': parseInt($(this).attr("title")) }
        })
        .done(function (data) {
            //Process MVC Data here
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            //Process Failure here
        });
    });
Dominic Sputo
fuente
0

Ligera mejora a la solución 360Airwalk. Esto incrusta el token Anti falsificación dentro de la función de JavaScript, por lo que @ Html.AntiForgeryToken () ya no necesita ser incluido en cada vista.

$(document).ready(function () {
    var securityToken = $('@Html.AntiForgeryToken()').attr('value');
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});
Barry MSIH
fuente
0
function DeletePersonel(id) {

    var data = new FormData();
    data.append("__RequestVerificationToken", "@HtmlHelper.GetAntiForgeryToken()");

    $.ajax({
        type: 'POST',
        url: '/Personel/Delete/' + id,
        data: data,
        cache: false,
        processData: false,
        contentType: false,
        success: function (result) {
        }
    });
}

public static class HtmlHelper {
    public static string GetAntiForgeryToken() {
        System.Text.RegularExpressions.Match value = 
                System.Text.RegularExpressions.Regex.Match(System.Web.Helpers.AntiForgery.GetHtml().ToString(), 
                        "(?:value=\")(.*)(?:\")");
        if (value.Success) {
            return value.Groups[1].Value;
        }
        return "";
    }
}
ismail eski
fuente
0

Estoy usando una publicación ajax para ejecutar un método de eliminación (resulta ser de una línea de tiempo de visjs pero eso no es relevante). Esto es lo que digo:

Este es mi Index.cshtml

@Scripts.Render("~/bundles/schedule")
@Styles.Render("~/bundles/visjs")
@Html.AntiForgeryToken()

<!-- div to attach schedule to -->
<div id='schedule'></div>

<!-- div to attach popups to -->
<div id='dialog-popup'></div>

Todo lo que agregué aquí fue @Html.AntiForgeryToken() hacer que el token apareciera en la página

Luego, en mi publicación de ajax, utilicé:

$.ajax(
    {
        type: 'POST',
        url: '/ScheduleWorks/Delete/' + item.id,
        data: {
            '__RequestVerificationToken': 
            $("input[name='__RequestVerificationToken']").val()
              }
     }
);

Que agrega el valor del token, raspado de la página, a los campos publicados

Antes de esto intenté poner el valor en los encabezados pero obtuve el mismo error

Siéntase libre de publicar mejoras. Esto ciertamente parece ser un enfoque simple que puedo entender.

Nick.McDermaid
fuente
0

De acuerdo, muchas publicaciones aquí, ninguna de ellas me ayudó, días y días de google, y aún no llegué al punto de escribir toda la aplicación desde cero, y luego noté esta pequeña pepita en mi Web.confg

 <httpCookies requireSSL="false" domain="*.localLookup.net"/>

Ahora no sé por qué lo agregué, sin embargo, ya lo noté, se ignora en modo de depuración y no en modo de producción (IE instalado en IIS en algún lugar)

Para mí, la solución era una de 2 opciones, ya que no recuerdo por qué lo agregué, no puedo estar seguro de que otras cosas no dependan de él, y en segundo lugar, el nombre de dominio debe estar en minúsculas y un TLD no como lo he hecho. en * .localLookup.net

Tal vez ayuda, tal vez no. Espero que ayude a alguien

Agitado
fuente
0

La solución que encontré no es para ASPX sino para Razor, sino un problema bastante competitivo.

Lo resolví agregando el AntiForgery a la solicitud. HTML Helper no crea una identificación HTML con la llamada

@Html.AntiForgeryToken()

Para agregar el token a la solicitud posterior, acabo de agregar la identificación de AntiForgery al campo oculto con jquery:

$("input[name*='__RequestVerificationToken']").attr('id', '__AjaxAntiForgeryForm');

Esto provocó que el controlador aceptara la solicitud con el atributo [ValidateAntiForgeryToken]

Dominik Sand
fuente
-3

AntiforgeryToken sigue siendo un dolor, ninguno de los ejemplos anteriores funcionó palabra por palabra para mí. Demasiados para allí. Así que los combiné todos. Necesita un @ Html.AntiforgeryToken en una forma dando vueltas por iirc

Resuelto así:

function Forgizzle(eggs) {
    eggs.__RequestVerificationToken =  $($("input[name=__RequestVerificationToken]")[0]).val();
    return eggs;
}

$.ajax({
            url: url,
            type: 'post',
            data: Forgizzle({ id: id, sweets: milkway }),
});

En caso de duda, agregue más signos $

Hazza
fuente