chamadas jQuery Ajax e o Html.AntiForgeryToken ()

207

Eu implementei no meu aplicativo a atenuação de ataques CSRF, seguindo as informações que li em algum post de blog na Internet. Em particular, este post foi o driver da minha implementação

Basicamente, esses artigos e recomendações afirmam que, para impedir o ataque do CSRF, qualquer pessoa deve implementar o seguinte código:

1) Adicione o [ValidateAntiForgeryToken]em todas as ações que aceitam o verbo POST Http

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

2) Adicione o <%= Html.AntiForgeryToken() %>auxiliar nos formulários que enviam dados ao servidor

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

De qualquer forma, em algumas partes do meu aplicativo, eu estou fazendo POSTs do Ajax com jQuery para o servidor sem ter nenhum formato. Isso acontece, por exemplo, em que estou permitindo que o usuário clique em uma imagem para executar uma ação específica.

Suponha que eu tenha uma tabela com uma lista de atividades. Eu tenho uma imagem em uma coluna da tabela que diz "Marcar atividade como concluída" e quando o usuário clica nessa atividade, estou executando o Ajax POST, como no exemplo a seguir:

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

Como posso usar o <%= Html.AntiForgeryToken() %>nesses casos? Devo incluir a chamada auxiliar dentro do parâmetro de dados da chamada Ajax?

Desculpe pelo longo post e muito obrigado por ajudar

EDIT :

De acordo com a resposta do jayrdub , usei da seguinte maneira

$("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
fonte
A ligação David Hayden agora 404s, parece que ele está migrou seu blog para um novo CMS, mas não migrar todo o conteúdo antigo acabou.

Respostas:

252

Eu uso uma função js simples como esta

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

Como todos os formulários de uma página terão o mesmo valor para o token, basta colocar algo assim na sua página principal

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

Em seguida, na sua chamada ajax do (editada para corresponder ao seu segundo exemplo)

$.ajax({
    type: "post",
    dataType: "html",
    url: $(this).attr("rel"),
    data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
    success: function (response) {
        // ....
    }
});
JeremyWeir
fonte
6
Bom, eu gosto do encapsulamento da busca de token.
jball
2
@ Lorenzo, coloque seus dados personalizados dentro da chamada para AddAntiForgeryToken, assim:data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
jball
3
Quão ruim seria uma idéia usar ajaxSendou substituir ajaxpara sempre aumentar datacom o token anti-falsificação? Talvez adicione alguma verificação para garantir que o urldestino seja destinado ao seu servidor.
ta.speot.is
1
Tenha cuidado se você usar o cache de saída.
Barbaros Alp
1
@SouhaiebBesbes o token de validação deve ser o mesmo para um usuário em todas as páginas (ele funciona em conjunto com um cookie definido e permanece o mesmo). Portanto, não importa se houver várias solicitações por página, será o mesmo se a página base for recarregada de qualquer maneira.
JeremyWeir
29

Gosto da solução fornecida pelo 360Airwalk, mas ela pode ser melhorada um pouco.

O primeiro problema é que, se você criar $.post()dados vazios, o jQuery não adiciona um Content-Typecabeçalho e, nesse caso, o ASP.NET MVC falha ao receber e verificar o token. Então você precisa garantir que o cabeçalho esteja sempre lá.

Outra melhoria é o suporte a todos os verbos HTTP com conteúdo : POST, PUT, DELETE etc. símbolo.

$(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
fonte
1
+1 você está certo, não pensei no problema de pós-chamada vazio. Obrigado pela contribuição. você estava certo quanto ao fato de não usarmos excluir / colocar ainda em nosso projeto.
360Airwalk
2
+1 para me salvar de ter que adicionar a função para todas as chamadas jQuery.ajax
Dragos Durlut
2
+1 Apenas como uma observação para a posteridade, a documentação do jQuery para os .ajaxSend()estados "No jQuery 1.8, o método .ajaxSend () deve ser anexado apenas ao documento". api.jquery.com/ajaxsend
RJ Cuthbertson
1
@Bronx De onde optionsvem, que está listado na ifdeclaração final ? Obrigado.
precisa saber é o seguinte
Cuidado com isso se você tiver vários formulários em uma página. Você precisará definir o valor em beforeSend com uma chamada de seletor mais específica, em vez de no documento.
Dan
22

Eu sei que existem muitas outras respostas, mas este artigo é bom e conciso e obriga você a verificar todos os seus HttpPosts, não apenas alguns deles:

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

Ele usa cabeçalhos HTTP em vez de tentar modificar a coleção de formulários.

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 () {
        ...
    }
});
vigilância
fonte
4
O atributo do artigo que você vinculou também combinado com a resposta do Bronx é a solução DRY definitiva para esse problema.
TugboatCaptain
2
Ótima descoberta. Editei sua resposta para incluir os trechos de código, para que a resposta seja por si só, mas espero que as pessoas leiam o restante do artigo também. Esta parece ser uma solução muito limpa.
Tim Medora
obrigado Tim, é uma excelente ideia, é frustrante quando um link fica inoperante e a resposta se torna inútil. Comecei a fazer isso em todas as minhas novas respostas.
viggity 29/07
Isso é MVC, WebAPI ou .NetCore? Não consigo obter os namespaces corretos para WebAPI 5
Myster
20

Sinto-me como um necromante avançado aqui, mas isso ainda é um problema 4 anos depois no MVC5.

Para lidar com solicitações de ajax corretamente, o token anti-falsificação precisa ser passado para o servidor em chamadas de ajax. A integração nos dados e modelos de postagem é confusa e desnecessária. Adicionar o token como um cabeçalho personalizado é limpo e reutilizável - e você pode configurá-lo para não precisar se lembrar de fazê-lo todas as vezes.

Há uma exceção - o ajax discreto não precisa de tratamento especial para chamadas de ajax. O token é passado normalmente no campo de entrada oculta regular. Exatamente o mesmo que um POST comum.

_Layout.cshtml

No _layout.cshtml, tenho esse bloco JavaScript. Ele não grava o token no DOM, mas usa o jQuery para extraí-lo do literal de entrada oculto que o MVC Helper gera. A seqüência mágica que é o nome do cabeçalho é definida como uma constante na classe 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>

Observe o uso de aspas simples na função beforeSend - o elemento de entrada que é renderizado usa aspas duplas que quebrariam o literal JavaScript.

JavaScript do cliente

Quando isso é executado, a função beforeSend acima é chamada e o AntiForgeryToken é adicionado automaticamente aos cabeçalhos da solicitação.

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

Biblioteca do Servidor

É necessário um atributo personalizado para processar o token não padrão. Isso se baseia na solução da @ viggity, mas lida com ajax discreto corretamente. Esse código pode ser escondido em sua biblioteca comum

[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

Agora você acabou de aplicar o atributo à sua ação. Melhor ainda, você pode aplicar o atributo ao seu controlador e todos os pedidos serão validados.

[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
  return Json(true, JsonRequestBehavior.DenyGet);
}
Will D
fonte
Solução perfeita, muito mais centralizada. Obrigado
David Freire
Você pode explicar com mais detalhes por que você deseja adicionar apenas o cabeçalho para URLs relativos? Isso passou pela minha cabeça. Ótima solução!
MattM
relativo garante que o cabeçalho seja definido apenas em solicitações que retornem ao seu próprio servidor, como a configuração do ajax cobre todas as solicitações feitas com jquery, não queremos que o token seja enviado nos requets jsonp ou CORS. Talvez isso também seja verdade para URLs absolutos, mas é garantido que o relativo seja o mesmo domínio.
A D
1
@ WillD Gostei da sua solução, mas fui forçado a modificá-la um pouco. Como você escolhe $.ajaxSetupdefinir um beforesendmanipulador de eventos geral , pode ser que você o substitua. Encontrei outra solução onde você pode adicionar um segundo manipulador que também será chamado. Funciona bem e não interrompe sua implementação.
Viper
Alguém tem uma versão ASP.net 5 do cliente validar o atributo AntiForgery? Esta versão não compila na versão mais recente!
Rob McCabe
19

Não use Html.AntiForgeryToken . Em vez disso, use AntiForgery.GetTokens e AntiForgery.Validate da API da Web, conforme descrito em Impedindo ataques de falsificação de solicitação entre sites (CSRF) no aplicativo ASP.NET MVC .

Edward Brey
fonte
Para métodos de ação do controlador que modelam vincular um tipo de modelo de servidor ao AJAX JSON publicado, é necessário ter o tipo de conteúdo como "application / json" para que o fichário de modelo apropriado seja usado. Infelizmente, isso impede o uso de dados de formulário, exigidos pelo atributo [ValidateAntiForgeryToken], portanto seu método é a única maneira que eu poderia encontrar para fazê-lo funcionar. Minha única pergunta é: ele ainda funciona em um farm da Web ou em várias instâncias de função da Web do Azure? Você @ Edward, ou alguém mais sabe se isso é um problema?
Richard B
@ Edward Brey Você pode explicar por que não devemos usá-lo?
Odys
4
@ Odys: Não há nada inerentemente errado com o Html.AntiForgeryToken, mas possui desvantagens: requer um formulário, requer jQuery e assume detalhes de implementação não documentados do Html.AntiForgeryToken. Ainda assim, é bom em muitos contextos. Minha declaração "Não use Html.AntiForgeryToken" provavelmente sai muito forte. Meu significado é que ele não deve ser usado com a API da Web, enquanto o AntiForgery.GetTokens é mais flexível.
Edward Brey
THX! Eu tive que mudar um pouco para torná-lo trabalhar para um controlador MVC5, mas esta foi a solução
jao
3
Certamente não requer um formulário. Você só precisa analisar o DOM por nome. Usando jquery, posso adicioná-lo dentro do meu objeto de dados por meio de dados {__RequestVerificationToken: $ ("input [name = __ RequestVerificationToken]"). Val ()}
Anthony Mason
16

Eu estava apenas implementando esse problema real no meu projeto atual. Eu fiz isso para todos os ajax-POSTs que precisavam de um usuário autenticado.

Primeiro, decidi ligar minhas chamadas jquery ajax, para não me repetir com muita frequência. esse snippet javascript garante que todas as chamadas ajax (post) adicionem meu token de validação de solicitação à solicitação. Nota: o nome __RequestVerificationToken é usado pela estrutura .Net para que eu possa utilizar os recursos padrão do Anti-CSRF, como mostrado abaixo.

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

Nas vistas em que você precisa que o token esteja disponível para o javascript acima, basta usar o HTML-Helper comum. Basicamente, você pode adicionar esse código onde quiser. Coloquei-o em uma instrução if (Request.IsAuthenticated):

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

No seu controlador, basta usar o mecanismo padrão do ASP.Net MVC Anti-CSRF. Eu fiz assim (embora eu realmente usei Salt).

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

Com o Firebug ou uma ferramenta similar, você pode ver facilmente como suas solicitações POST agora têm um parâmetro __RequestVerificationToken anexado.

360Airwalk
fonte
15

Acho que tudo que você precisa fazer é garantir que a entrada "__RequestVerificationToken" esteja incluída na solicitação POST. A outra metade das informações (ou seja, o token no cookie do usuário) já é enviada automaticamente com uma solicitação AJAX POST.

Por exemplo,

$("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
fonte
1
Depois de muitas horas experimentando a postagem do jQuery AJAX em uma página do MVC (Razor), essa foi a resposta mais simples de tudo que funcionou para mim. Basta incluir seus próprios campos de dados (ou o viewModel, suponho) após o token como uma nova parte de dados (mas dentro do objeto de dados original).
Ralph Bacon
Como eu implementaria isso se a função AJAX estivesse em uma página .html e não em uma página do Razor?
Bob o Construtor
Se a sua página html não possui um servidor fornecido AntiForgeryToken, é discutível. Se isso acontecer (sem saber como você está conseguindo um nesse caso, mas supondo que esteja), o procedimento acima funcionaria perfeitamente. Se você estiver tentando criar uma página da Web simples que postará uma solicitação em um servidor esperando o referido token e o servidor não gerou a página, você estará sem sorte. Isso é essencialmente o ponto da AntiForgeryToken ...
jball
6

Você também pode fazer isso:

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

Isso está sendo usado Razor, mas se você estiver usando WebFormssintaxe, também poderá usar <%= %>tags

Leonardo Garcia Crespo
fonte
4

Além do meu comentário contra a resposta da @ JBall que me ajudou ao longo do caminho, esta é a resposta final que funciona para mim. Estou usando o MVC e o Razor e estou enviando um formulário usando o jQuery AJAX para poder atualizar uma exibição parcial com alguns resultados novos e não desejar fazer uma postagem completa (e oscilação da página).

Adicione o @Html.AntiForgeryToken()interior do formulário como de costume.

Meu código do botão de envio AJAX (ou seja, um 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');
    }
});

Deixei a ação "success", pois mostra como a exibição parcial está sendo atualizada que contém um MvcJqGrid e como está sendo atualizada (grade jqGrid muito poderosa e esse é um brilhante wrapper MVC para ele).

Meu método de controlador é assim:

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

Eu tenho que admitir que não sou um fã de postar dados de um formulário inteiro como um modelo, mas se você precisar fazer isso, essa é uma maneira de funcionar. O MVC apenas facilita muito a ligação de dados, em vez de subornar 16 valores individuais (ou um FormCollection de tipo fraco), tudo bem, eu acho. Se você souber melhor, informe-me, pois quero produzir um código MVC C # robusto.

Ralph Bacon
fonte
4

encontrou essa ideia muito inteligente em https://gist.github.com/scottrippey/3428114 para cada chamada de $ .ajax, modifica a solicitação e adiciona o 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
fonte
Eu tentei várias das outras alternativas acima, é isso que resolveu para mim.
HostMyBus 25/04/19
Eu fiz no entanto tem que adicionar if (options.contentType != false && options.contentType.indexOf('application/json') === 0) {para pegar chamadas Ajax que não tinha especificado um tipo de conteúdo
HostMyBus
3

1.Define a função para obter o token do servidor

@function
{

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

2. Obtenha o token e defina o cabeçalho antes de enviar para o servidor

var token = '@TokenHeaderValue()';    

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

3. Validação Onserver no HttpRequestBase no método que você lida com 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);
Tonman Neverwalk sozinho
fonte
1

Sei que já faz algum tempo desde que esta pergunta foi publicada, mas achei um recurso realmente útil, que discute o uso do AntiForgeryToken e o torna menos problemático de usar. Ele também fornece o plugin jquery para incluir facilmente o token antiforgery nas chamadas AJAX:

Receitas de solicitações antifalsificação para ASP.NET MVC e AJAX

Não estou contribuindo muito, mas talvez alguém ache útil.

slawek
fonte
Esse post é como uma milha de comprimento! Eu tenho certeza que é grande, mas tl; dr
BritishDeveloper
1
Que pena, porque cobre bem o assunto. Ele não apenas mostra como usar o recurso, mas explica qual problema ele corrige e fornece contexto para entender como usá-lo corretamente. Quando se trata de segurança, acho que é importante compreender profundamente.
slawek
2
Se é importante ele deve ser escrito de uma forma que encoraja as pessoas a lê-lo;)
BritishDeveloper
1

primeiro use @ Html.AntiForgeryToken () em 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
fonte
1

Aqui está a maneira mais fácil que eu já vi. Nota: verifique se você tem "@ Html.AntiForgeryToken ()" na sua exibição.

  $("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
fonte
0

Pequena melhoria na solução 360Airwalk. Isso imbui o token anti-falsificação dentro da função javascript, portanto, @ Html.AntiForgeryToken () não precisa mais ser incluído em todas as visualizações.

$(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
fonte
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
fonte
0

Estou usando uma postagem do ajax para executar um método de exclusão (acontece de uma linha do tempo visjs, mas isso não é relelvant). Isto é o que eu sis:

Este é o meu 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>

Tudo o que eu adicionei aqui foi @Html.AntiForgeryToken() fazer o token aparecer na página

Então, no meu post do ajax, usei:

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

O que adiciona o valor do token, raspado da página, aos campos postados

Antes disso, tentei colocar o valor nos cabeçalhos, mas recebi o mesmo erro

Sinta-se livre para publicar melhorias. Esta certamente parece ser uma abordagem simples que eu posso entender

Nick.McDermaid
fonte
0

Ok, muitas postagens aqui, nenhuma delas me ajudou, dias e dias do google, e ainda não cheguei ao ponto de escrever o aplicativo inteiro do zero, e então notei essa pequena pepita no meu Web.confg

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

Agora não sei por que o adicionei, mas notei que ele é ignorado no modo de depuração e não no modo de produção (IE instalado no IIS em algum lugar)

Para mim, a solução era uma das duas opções, já que não me lembro por que a adicionei. Não posso ter certeza de que outras coisas não dependem dela. Segundo, o nome do domínio deve estar em letras minúsculas e um TLD não como o feito. em * .localLookup.net

Talvez ajude, talvez não. Espero que ajude alguém

Agitado
fonte
0

A solução que encontrei não é para o ASPX, mas para o Razor, mas é um problema bastante agradável.

Eu o resolvi adicionando o AntiForgery à solicitação. O HTML Helper não cria um ID HTML com a chamada

@Html.AntiForgeryToken()

Para adicionar o token ao póstrequest, adicionei o ID do AntiForgery ao campo oculto com jquery:

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

Isso fez com que o controlador aceite a solicitação com o atributo [ValidateAntiForgeryToken]

Dominik Sand
fonte
-3

O antiforgeryToken ainda é uma dor, nenhum dos exemplos acima funcionou palavra por palavra para mim. Muitos para estão lá. Então eu combinei todos eles. Precisa de um @ Html.AntiforgeryToken em um formulário pendurado no iirc

Resolvido da seguinte forma:

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

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

Em caso de dúvida, adicione mais sinais de $

Hazza
fonte