jQuery Ajax chiama e Html.AntiForgeryToken ()


207

Ho implementato nella mia app la mitigazione degli attacchi CSRF seguendo le informazioni che ho letto su alcuni post di blog su Internet. In particolare questi post sono stati il ​​motore della mia implementazione

Fondamentalmente quegli articoli e raccomandazioni dicono che per prevenire l'attacco CSRF qualcuno dovrebbe implementare il seguente codice:

1) Aggiungi [ValidateAntiForgeryToken]tutte le azioni che accettano il verbo POST Http

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

2) Aggiungi l' <%= Html.AntiForgeryToken() %>helper all'interno dei moduli che invia i dati al server

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

Comunque in alcune parti della mia app sto facendo Ajax POST con jQuery sul server senza avere alcuna forma. Questo accade ad esempio quando lascio che l'utente faccia clic su un'immagine per eseguire un'azione specifica.

Supponiamo di avere una tabella con un elenco di attività. Ho un'immagine su una colonna della tabella che dice "Segna attività come completata" e quando l'utente fa clic su quell'attività sto facendo Ajax POST come nel seguente esempio:

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

Come posso usare il <%= Html.AntiForgeryToken() %>in questi casi? Devo includere la chiamata dell'helper all'interno del parametro data della chiamata Ajax?

Ci scusiamo per il lungo post e grazie mille per l'aiuto

MODIFICA :

Come da risposta jayrdub ho usato nel modo seguente

$("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) {
            // ....
        }
    });
});

Il link di David Hayden ora 404s, sembra che abbia migrato il suo blog su un nuovo CMS, ma non abbia migrato tutto il vecchio contenuto.

Risposte:


252

Uso una semplice funzione js come questa

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

Poiché ogni modulo in una pagina avrà lo stesso valore per il token, inserisci qualcosa di simile nella tua pagina principale più in alto

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

Quindi nella tua chiamata Ajax fai (modificato per abbinare il tuo secondo esempio)

$.ajax({
    type: "post",
    dataType: "html",
    url: $(this).attr("rel"),
    data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
    success: function (response) {
        // ....
    }
});

6
Bello, mi piace l'incapsulamento del token fetching.
jball

2
@Lorenzo, inserisci i tuoi dati personalizzati all'interno della chiamata AddAntiForgeryToken, in questo modo:data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
jball

3
Quanto sarebbe un'idea brutta da usare ajaxSendo ignorare ajaxper aumentare sempre datacon il token anti-contraffazione? Forse aggiungendo un po 'di controllo per assicurarsi che urlsia destinato al tuo server.
ta.speot.is

1
Fai attenzione se usi la cache di output.
Barbaros Alp

1
@SouhaiebBesbes il token di convalida dovrebbe essere lo stesso per un utente su tutte le pagine (funziona in combinazione con un cookie impostato e rimane lo stesso). Quindi non importa se ci sono più richieste per pagina, sarà lo stesso se la pagina di base viene ricaricata comunque.
JeremyWeir,

29

Mi piace la soluzione fornita da 360Airwalk, ma potrebbe essere leggermente migliorata.

Il primo problema è che se si effettua $.post()con dati vuoti, jQuery non aggiunge Content-Typeun'intestazione e in questo caso ASP.NET MVC non riesce a ricevere e controllare il token. Quindi devi assicurarti che l'intestazione sia sempre lì.

Un altro miglioramento è il supporto di tutti i verbi HTTP con contenuto : POST, PUT, DELETE ecc. Sebbene sia possibile utilizzare solo POST nella propria applicazione, è meglio disporre di una soluzione generica e verificare che tutti i dati ricevuti con qualsiasi verbo abbiano un anti-contraffazione gettone.

$(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);
            }
        }
    });
});

1
+1 hai ragione, non ho pensato al problema del post post call vuoto. Grazie per l'input. avevi ragione sul fatto che non usiamo ancora cancellare / mettere nel nostro progetto.
360Airwalk,

2
+1 per avermi salvato dal dover aggiungere la funzione a tutti i jQuery.Ajax chiama
Dragos Durlut

2
+1 Proprio come una nota per i posteri, la documentazione di jQuery per gli .ajaxSend()stati "A partire da jQuery 1.8, il metodo .ajaxSend () deve essere allegato solo al documento." api.jquery.com/ajaxsend
RJ Cuthbertson,

1
@Bronx Da dove optionsviene, che è elencato nella ifdichiarazione finale ? Grazie.
hvaughan3,

Fai attenzione se utilizzi più moduli in una pagina. Sarà necessario impostare il valore in beforeInvia con una chiamata selettore più specifica anziché per il documento.
Dan,

22

So che ci sono molte altre risposte, ma questo articolo è carino e conciso e ti costringe a controllare tutti i tuoi HttpPost, non solo alcuni di essi:

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

Utilizza le intestazioni HTTP invece di provare a modificare la raccolta di moduli.

server

//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 () {
        ...
    }
});

4
L'attributo dell'articolo che hai collegato troppo in combinazione con la risposta del Bronx è la soluzione DRY definitiva a questo problema.
TugboatCaptain

2
Grande scoperta. Ho modificato la tua risposta per includere gli snippet di codice in modo che la risposta sia autonoma, ma spero che la gente leggerà anche il resto dell'articolo. Questa sembra essere una soluzione molto pulita.
Tim Medora,

grazie Tim, è un'ottima idea, è frustrante quando un collegamento si interrompe e la risposta diventa inutile. Ho iniziato a farlo con tutte le mie nuove risposte.
vigore

Questo è MVC, WebAPI o .NetCore? Non riesco a ottenere gli spazi dei nomi corretti per WebAPI 5
Myster

20

Mi sento come un negromante avanzato qui, ma questo è ancora un problema 4 anni dopo in MVC5.

Per gestire correttamente le richieste Ajax, il token anti-contraffazione deve essere passato al server durante le chiamate Ajax. L'integrazione nei dati e nei modelli dei tuoi post è disordinata e non necessaria. L'aggiunta del token come intestazione personalizzata è pulita e riutilizzabile e puoi configurarla in modo da non doverti ricordare di farlo ogni volta.

C'è un'eccezione: ajax discreto non richiede un trattamento speciale per le chiamate ajax. Il token viene passato come al solito nel normale campo di input nascosto. Esattamente come un normale POST.

_Layout.cshtml

In _layout.cshtml ho questo blocco JavaScript. Non scrive il token nel DOM, ma utilizza jQuery per estrarlo dal valore letterale di input nascosto generato dall'helper MVC. La stringa magica che è il nome dell'intestazione è definita come costante nella classe dell'attributo.

<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>

Nota l'uso di virgolette singole nella funzione beforeSend: l'elemento di input che viene reso utilizza virgolette doppie che rompono il valore letterale JavaScript.

JavaScript client

Quando viene eseguita, viene chiamata la funzione beforeSend sopra e AntiForgeryToken viene automaticamente aggiunto alle intestazioni della richiesta.

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

Libreria del server

È necessario un attributo personalizzato per elaborare il token non standard. Questo si basa sulla soluzione di @ viggity, ma gestisce correttamente ajax discreto. Questo codice può essere nascosto nella tua libreria comune

[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);
            }
        }
    }
}

Server / Controller

Ora applichi semplicemente l'attributo alla tua azione. Ancora meglio puoi applicare l'attributo al tuo controller e tutte le richieste saranno validate.

[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
  return Json(true, JsonRequestBehavior.DenyGet);
}

Soluzione perfetta, molto più centralizzata. Grazie
David Freire il

Puoi spiegare in modo più dettagliato perché desideri aggiungere solo l'intestazione per gli URL relativi? Mi è passato per la testa. Ottima soluzione!
MattM

relative garantisce che l'intestazione sia impostata solo su richieste che risalgono al proprio server, poiché l'installazione di Ajax copre tutte le richieste fatte con jquery, non vogliamo che il token venga inviato su jsonp o requisiti CORS. Questo potrebbe essere vero anche per gli URL assoluti, ma i relativi sono garantiti per essere lo stesso dominio.
Will D

1
@WillD Mi è piaciuta la tua soluzione, ma sono stata costretta a modificarla un po '. Poiché si sceglie $.ajaxSetupdi definire un beforesendgestore eventi generale , può succedere che lo si sovrascriva. Ho trovato un'altra soluzione in cui è possibile aggiungere un secondo gestore che verrà anche chiamato. Funziona bene e non interrompe la tua implementazione.
Viper

Qualcuno ha una versione ASP.net 5 del cliente che convalida l'attributo AntiForgery? Questa versione non viene compilata nell'ultima versione!
Rob McCabe,

19

Non usare Html.AntiForgeryToken . Utilizzare invece AntiForgery.GetTokens e AntiForgery.Validate dall'API Web come descritto in Prevenzione degli attacchi CSRF (Cross-Site Request Forgery) nell'applicazione ASP.NET MVC .


Per i metodi di azione del controller che un modello associa un tipo di modello di server al JSON AJAX pubblicato, è necessario avere il tipo di contenuto "application / json" per utilizzare il raccoglitore modello corretto. Sfortunatamente, ciò preclude l'utilizzo dei dati del modulo, richiesti dall'attributo [ValidateAntiForgeryToken], quindi il tuo metodo è l'unico modo che ho potuto trovare per farlo funzionare. La mia unica domanda è: funziona ancora in una Web farm o in più istanze di ruoli Web di Azure? @Edward o qualcun altro sa se questo è un problema?
Richard B,

@Edward Brey Puoi per favore approfondire il motivo per cui non dovremmo usarlo?
Odys,

4
@Odys: non c'è nulla di intrinsecamente sbagliato in Html.AntiForgeryToken, ma ha degli aspetti negativi: richiede un modulo, richiede jQuery e assume i dettagli di implementazione Html.AntiForgeryToken non documentati. Comunque, va bene in molti contesti. La mia affermazione "Non usare Html.AntiForgeryToken" probabilmente risulta troppo forte. Il mio significato è che non è destinato all'uso con l'API Web, mentre AntiForgery.GetTokens è più flessibile.
Edward Brey,

grazie! Ho dovuto cambiarlo un po 'per farlo funzionare per un controller MVC5, ma questa era la soluzione
jao

3
Certamente non richiede un modulo. Devi solo analizzare il DOM per nome. Usando jquery, posso aggiungerlo all'interno del mio oggetto dati tramite i dati {__RequestVerificationToken: $ ("input [nome = __ RequestVerificationToken]"). Val ()}
Anthony Mason,

16

Stavo solo implementando questo vero problema nel mio attuale progetto. l'ho fatto per tutti i POST Ajax che necessitavano di un utente autenticato.

Prima di tutto ho deciso di agganciare le mie chiamate ajax jquery, quindi non mi ripeto troppo spesso. questo snippet javascript assicura che tutte le chiamate ajax (post) aggiungano il token di convalida della mia richiesta alla richiesta. Nota: il nome __RequestVerificationToken viene utilizzato dal framework .Net in modo da poter utilizzare le funzionalità standard Anti-CSRF come mostrato di seguito.

$(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);
            }
        }
    });
});

Nelle viste in cui è necessario che il token sia disponibile per il javascript sopra riportato, basta usare il comune HTML-Helper. Puoi praticamente aggiungere questo codice dove vuoi. L'ho inserito in un'istruzione if (Request.IsAuthenticated):

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

Nel controller è sufficiente utilizzare il meccanismo ASP.Net MVC Anti-CSRF standard. L'ho fatto in questo modo (anche se in realtà ho usato Salt).

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

Con Firebug o uno strumento simile puoi facilmente vedere come le tue richieste POST ora hanno un parametro __RequestVerificationToken aggiunto.


15

Penso che tutto ciò che devi fare è assicurarti che l'ingresso "__RequestVerificationToken" sia incluso nella richiesta POST. L'altra metà delle informazioni (ovvero il token nel cookie dell'utente) viene già inviata automaticamente con una richiesta POST AJAX.

Per esempio,

$("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) {
            // ....
        }
    });
});

1
Dopo molte ore di sperimentazione con la pubblicazione di jQuery AJAX da una pagina MVC (Razor), questa è stata la risposta più semplice di tutto ciò che ha funzionato per me. Includi semplicemente i tuoi campi dati (o il viewModel suppongo) dopo il token come nuovo pezzo di dati (ma all'interno dell'oggetto dati originale).
Ralph Bacon,

Come implementerei questo se la funzione AJAX fosse in una pagina .html e non in una pagina Razor?
Bob the Builder,

Se la tua pagina html non ha un server fornito, AntiForgeryTokenè comunque tutto discutibile. In tal caso (non sono sicuro di come se ne ottenga uno in quel caso, ma supponendo che lo sia), allora quanto sopra funzionerebbe bene. Se stai tentando di creare una semplice pagina Web che invierà una richiesta a un server in attesa di tale token e il server non ha generato tale pagina, allora sei sfortunato. Questo è essenzialmente il punto dell'AntiForgeryToken ...
jball

6

Puoi farlo anche:

$("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) {
        // ....
        }
    });
});

Questo sta usando Razor, ma se stai usando la WebFormssintassi puoi usare anche i <%= %>tag


4

Oltre al mio commento contro la risposta di @ JBall che mi ha aiutato lungo la strada, questa è la risposta finale che funziona per me. Sto usando MVC e Razor e sto inviando un modulo usando jQuery AJAX in modo da poter aggiornare una vista parziale con alcuni nuovi risultati e non volevo fare un postback completo (e sfarfallio della pagina).

Aggiungi l' @Html.AntiForgeryToken()interno del modulo come al solito.

Il mio codice del pulsante di invio AJAX (ovvero un evento onclick) è:

//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');
    }
});

Ho lasciato l'azione "successo" in quanto mostra come viene aggiornata la vista parziale che contiene un MvcJqGrid e come viene aggiornata (griglia jqGrid molto potente e questo è un wrapper MVC brillante per questo).

Il mio metodo controller è simile al seguente:

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

Devo ammettere di non essere un fan di PUBBLICARE i dati di un intero modulo come modello, ma se è necessario farlo, questo è un modo che funziona. MVC rende semplicemente l'associazione dei dati troppo semplice, quindi piuttosto che inviare 16 valori singoli (o un FormCollection debolmente tipizzato), va bene, immagino. Se conosci meglio, fammi sapere perché voglio produrre un codice C # MVC robusto.


4

ho trovato questa idea molto intelligente da https://gist.github.com/scottrippey/3428114 per ogni chiamata $ .ajax che modifica la richiesta e aggiunge il 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();
        }
    }
});

Ho provato diverse altre alternative sopra, questo è ciò che ha risolto per me.
HostMyBus

Tuttavia, ho dovuto aggiungere if (options.contentType != false && options.contentType.indexOf('application/json') === 0) {per intercettare le chiamate Ajax che non avevano specificato un tipo di contenuto
HostMyBus

3

1. Definire la funzione per ottenere il token dal server

@function
{

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

2.Prendi il token e imposta l'intestazione prima di inviarlo al server

var token = '@TokenHeaderValue()';    

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

3. Convalida sul server su HttpRequestBase sul metodo che gestisci Post / get

        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);

1

So che è passato del tempo da quando questa domanda è stata pubblicata, ma ho trovato una risorsa davvero utile, che discute l'uso di AntiForgeryToken e ne rende meno problematico l'uso. Fornisce inoltre plugin jquery per includere facilmente token antiforgery nelle chiamate AJAX:

Ricette richieste anti-contraffazione per ASP.NET MVC e AJAX

Non sto contribuendo molto, ma forse qualcuno lo troverà utile.


Quel post è lungo un miglio! Sono sicuro che è fantastico, ma il dott.
British Devevoper il

1
Peccato, perché copre bene il soggetto. Non solo ti spiega come utilizzare la funzione, ma spiega quale problema risolve e ti fornisce un contesto per capire come usarla correttamente. Per quanto riguarda la sicurezza, penso che una comprensione approfondita sia importante.
slawek,

2
Se è importante, dovrebbe essere scritto in un modo che incoraggi le persone a leggerlo;)
British Devevoper

1

primo utilizzo @ Html.AntiForgeryToken () in 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);
        }

1

Ecco il modo più semplice che ho visto. Nota: assicurati di avere "@ Html.AntiForgeryToken ()" nella 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
        });
    });

0

Leggero miglioramento alla soluzione 360Airwalk. Ciò incorpora il token Anti Forgery all'interno della funzione javascript, quindi @ Html.AntiForgeryToken () non deve più essere incluso in ogni 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);
            }
        }
    });
});

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 "";
    }
}

0

Sto usando un post Ajax per eseguire un metodo di eliminazione (sembra provenire da una sequenza temporale di Visjs ma non è un relelvant). Questo è ciò che sono:

Questo è il mio 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>

Tutto quello che ho aggiunto qui è stato @Html.AntiForgeryToken()quello di far apparire il token nella pagina

Quindi nel mio post Ajax ho usato:

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

Il che aggiunge il valore del token, cancellato dalla pagina, ai campi pubblicati

Prima di questo ho provato a inserire il valore nelle intestazioni ma ho avuto lo stesso errore

Sentiti libero di pubblicare miglioramenti. Questo certamente sembra essere un approccio semplice che posso capire


0

Va bene un sacco di post qui, nessuno di loro mi ha aiutato, giorni e giorni di google, e ancora non sono arrivato al punto di scrivere l'intera app da zero, e poi ho notato questa piccola pepita nel mio Web.confg

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

Ora non so perché l'ho aggiunto, come ho notato, è ignorato in modalità debug e non in modalità di produzione (IE installato su IIS Somewhere)

Per me la soluzione era una delle 2 opzioni, dal momento che non ricordo perché l'ho aggiunta, non posso essere sicuro che altre cose non dipendono da esso, e in secondo luogo il nome di dominio deve essere tutto minuscolo e un TLD non come ive done in * .localLookup.net

Forse aiuta, forse no. Spero che aiuti qualcuno


0

La soluzione che ho trovato non è per ASPX ma per Razor, ma è un problema abbastanza affidabile.

L'ho risolto aggiungendo l'AntiForgery alla richiesta. HTML Helper non crea un ID HTML con la chiamata

@Html.AntiForgeryToken()

Per aggiungere il token al postrequest ho appena aggiunto l'id AntiForgery al campo nascosto con jquery:

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

In questo modo il controller ha accettato la richiesta con l'attributo [ValidateAntiForgeryToken]


-3

AntiforgeryToken è ancora un dolore, nessuno degli esempi sopra ha funzionato parola per parola per me. Troppi per lì. Quindi li ho combinati tutti. Hai bisogno di un @ Html.AntiforgeryToken in una forma che gira intorno a iirc

Risolto così:

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

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

In caso di dubbio, aggiungi più segni $

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.