AVISO: Não é possível verificar os trilhos de autenticidade do token CSRF

238

Estou enviando dados do modo de exibição para o controlador com AJAX e recebi este erro:

AVISO: Não é possível verificar a autenticidade do token CSRF

Eu acho que tenho que enviar esse token com dados.

Alguém sabe como posso fazer isso?

Edit: Minha solução

Eu fiz isso colocando o seguinte código dentro da postagem do AJAX:

headers: {
  'X-Transaction': 'POST Example',
  'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
kbaccouche
fonte
7
você tem <% = csrf_meta_tag%> no cabeçalho do layout?
26611 Anatoly
sim como este: <% = csrf_meta_tags%>
kbaccouche
6
você tem bibliotecas jquery-rails que fornecem funcionalidade do lado do cliente ajax?
Anatoly
2
E a maneira HAML é adicionar "= csrf_meta_tags"
Ege Akpinar
boa pergunta, obrigado por perguntar
AMIC MING

Respostas:

374

Você deve fazer isso:

  1. Verifique se você tem <%= csrf_meta_tag %>em seu layout

  2. Adicione beforeSenda toda a solicitação ajax para definir o cabeçalho como abaixo:


$.ajax({ url: 'YOUR URL HERE',
  type: 'POST',
  beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
  data: 'someData=' + someData,
  success: function(response) {
    $('#someDiv').html(response);
  }
});

Para enviar token em todas as solicitações, você pode usar:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});
Chau Hong Linh
fonte
5
Obrigado! Trabalhou para mim como um encanto!
Misha Moroshko
35
A biblioteca UJS do jQuery fornecida pela equipe do Rails adiciona o token CSRF à solicitação do jQuery AJAX automaticamente. O README contém instruções sobre como obter a configuração. github.com/rails/jquery-ujs/blob/master/src/rails.js#L91
James Conroy-Finn
1
Observe que você pode definir o cabeçalho para todas as solicitações de uma só vez com a função $ .ajaxSetup.
Pieter Jongsma
1
Excelente! Estive procurando por um tempo para esta resposta. Funciona perfeitamente. Obrigado!
precisa saber é o seguinte
4
Como uma observação, se você estiver usando o jQuery UJS como sugerido acima, será necessário garantir que a inclusão do rails-ujs venha após a inclusão do jquery ou falhará com o mesmo erro do op.
Topher Fangio
31

A melhor maneira de fazer isso é usar apenas <%= form_authenticity_token.to_s %>para imprimir o token diretamente no seu código rails. Você não precisa usar o javascript para pesquisar o dom pelo token csrf, como outros posts mencionam. basta adicionar a opção de cabeçalhos como abaixo;

$.ajax({
  type: 'post',
  data: $(this).sortable('serialize'),
  headers: {
    'X-CSRF-Token': '<%= form_authenticity_token.to_s %>'
  },
  complete: function(request){},
  url: "<%= sort_widget_images_path(@widget) %>"
})
ADÃO
fonte
7
Em vez de fazer isso para cada comando ajax, você pode adicionar cabeçalhos a $ .ajaxSetup () .
Scott McMillin 29/11
1
Prefiro recomendar o uso desta resposta ...
opsidao
14
Eu realmente não gosto da abordagem de usar ERB no javascript.
Radixhound
Isso força você a gerar seu javascript com o ERB, o que é muito limitante. Mesmo que existam lugares onde o ERB possa ser adequado, há outros onde não é, e adicioná-lo apenas para obter o token seria um desperdício.
Sockmonk
22

Se bem me lembro, você deve adicionar o seguinte código ao seu formulário, para se livrar desse problema:

<%= token_tag(nil) %>

Não esqueça o parâmetro.

auralbee
fonte
8
Na verdade, este deve ser: <%= token_tag(nil) %>. Então você obtém o token gerado automaticamente.
Szeryf
15

De fato, a maneira mais simples. Não se preocupe em alterar os cabeçalhos.

Assegure-se de ter:

<%= csrf_meta_tag %> in your layouts/application.html.erb

Basta fazer um campo de entrada oculto da seguinte maneira:

<input name="authenticity_token" 
               type="hidden" 
               value="<%= form_authenticity_token %>"/>

Ou, se você quiser uma postagem do jQuery ajax:

$.ajax({     
    type: 'POST',
    url: "<%= someregistration_path %>",
    data: { "firstname": "text_data_1", "last_name": "text_data2", "authenticity_token": "<%= form_authenticity_token %>" },                                                                                  
    error: function( xhr ){ 
      alert("ERROR ON SUBMIT");
    },
    success: function( data ){ 
      //data response can contain what we want here...
      console.log("SUCCESS, data="+data);
    }
});
Walter Schreppers
fonte
Adicionar o campo de entrada oculto ao meu formulário de entrada resolveu o problema para mim.
Teemu Leisti 28/09
isso é feito automaticamente se você usar os auxiliares de formulário do Rails.
Jason FB
13

A atualização de um aplicativo mais antigo para o Rails 3.1, incluindo a metatag csrf ainda não está resolvendo isso. No blog rubyonrails.org, eles fornecem algumas dicas de atualização e, especificamente, esta linha de jquery, que deve estar na seção principal do seu layout:

$(document).ajaxSend(function(e, xhr, options) {
 var token = $("meta[name='csrf-token']").attr("content");
  xhr.setRequestHeader("X-CSRF-Token", token);
});

extraído desta postagem do blog: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails .

No meu caso, a sessão estava sendo redefinida a cada solicitação de ajax. A adição do código acima resolveu esse problema.

Danny
fonte
10
  1. Verifique se você tem <%= csrf_meta_tag %>em seu layout
  2. Adicione a beforeSendpara incluir o token csrf na solicitação ajax para definir o cabeçalho. Isso é necessário apenas para postsolicitações.

O código para ler o csrf-token está disponível no diretório rails/jquery-ujs, portanto, é mais fácil usá-lo da seguinte maneira:

$.ajax({
  url: url,
  method: 'post',
  beforeSend: $.rails.CSRFProtection,
  data: {
    // ...
  }
})
nathanvda
fonte
Simples sem reimplementar o que já está incluído no Rails. Essa deve ser a resposta selecionada.
jiehanzheng
No Rails 5.1 também funciona:headers: { 'X-CSRF-Token': Rails.csrfToken() }
olhor 15/03
@nathanvda, Talvez você possa responder a esta pergunta semelhante: stackoverflow.com/questions/50159847/...
6

As principais respostas votadas aqui estão corretas, mas não funcionarão se você estiver executando solicitações entre domínios, porque a sessão não estará disponível, a menos que você diga explicitamente ao jQuery para passar o cookie da sessão. Veja como fazer isso:

$.ajax({ 
  url: url,
  type: 'POST',
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
  },
  xhrFields: {
    withCredentials: true
  }
});
dreadwail
fonte
Posso perguntar se você pode responder a essa pergunta muito semelhante? stackoverflow.com/questions/50159847/…
5

Você pode escrevê-lo globalmente como abaixo.

JS normal:

$(function(){

    $('#loader').hide()
    $(document).ajaxStart(function() {
        $('#loader').show();
    })
    $(document).ajaxError(function() {
        alert("Something went wrong...")
        $('#loader').hide();
    })
    $(document).ajaxStop(function() {
        $('#loader').hide();
    });
    $.ajaxSetup({
        beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))}
    });
});

Script Café:

  $('#loader').hide()
  $(document).ajaxStart ->
    $('#loader').show()

  $(document).ajaxError ->
    alert("Something went wrong...")
    $('#loader').hide()

  $(document).ajaxStop ->
    $('#loader').hide()

  $.ajaxSetup {
    beforeSend: (xhr) ->
      xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
  }
Chezhian
fonte
5

oops ..

Eu perdi a seguinte linha no meu application.js

//= require jquery_ujs

Eu o substituí e está funcionando ..

======= ATUALIZADO =========

Após 5 anos, estou de volta com o mesmo erro, agora tenho o Rails 5.1.6 totalmente novo e encontrei este post novamente. Assim como o círculo da vida.

Agora, qual era o problema: o Rails 5.1 removeu o suporte para jquery e jquery_ujs por padrão e adicionou

//= require rails-ujs in application.js

Faz o seguinte:

  1. forçar diálogos de confirmação para várias ações;
  2. faça solicitações não GET a partir de hiperlinks;
  3. faça formulários ou hiperlinks enviar dados de forma assíncrona com o Ajax;
  4. os botões de envio são desativados automaticamente no envio de formulários para impedir o clique duplo. (de: https://github.com/rails/rails-ujs/tree/master )

Mas por que não está incluindo o token csrf para solicitação de ajax? Se alguém souber sobre isso em detalhes, basta comentar-me. Obrigado.

De qualquer forma, adicionei o seguinte no meu arquivo js personalizado para fazê-lo funcionar (obrigado por outras respostas para me ajudar a alcançar esse código):

$( document ).ready(function() {
  $.ajaxSetup({
    headers: {
      'X-CSRF-Token': Rails.csrfToken()
    }
  });
  ----
  ----
});
Abhi
fonte
Era isso que eu precisava fazer também. A razão pela qual isso surgiu é porque estou criando um aplicativo React para substituir lentamente um aplicativo Rails existente. Como há um monte de ruído javascript no aplicativo existente, criei um layout diferente que acessa um arquivo javascript diferente, mas não o incluí jquery_ujs. Esse foi o truque.
22417 Wylliam Judd
1
Sim, às vezes Se sentirmos falta disso ao refazer, refatorar algo ... é difícil descobrir o que está errado. Como não estamos fazendo nada manualmente para fazê-lo funcionar, o Rails o inclui automaticamente. Nós achamos que já está lá. Obrigado por esses sites sociais Qn / Ans
Abhi
Talvez você possa responder a essa pergunta semelhante: stackoverflow.com/questions/50159847/… #
4

Se você não estiver usando jQuery e usando algo como buscar API para solicitações, poderá usar o seguinte para obter csrf-token:

document.querySelector('meta[name="csrf-token"]').getAttribute('content')

fetch('/users', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')},
    credentials: 'same-origin',
    body: JSON.stringify( { id: 1, name: 'some user' } )
    })
    .then(function(data) {
      console.log('request succeeded with JSON response', data)
    }).catch(function(error) {
      console.log('request failed', error)
    })
svnm
fonte
Posso perguntar se você pode responder a essa pergunta muito semelhante? stackoverflow.com/questions/50159847/…
4

Use jquery.csrf ( https://github.com/swordray/jquery.csrf ).

  • Rails 5.1 ou posterior

    $ yarn add jquery.csrf
    //= require jquery.csrf
  • Rails 5.0 ou anterior

    source 'https://rails-assets.org' do
      gem 'rails-assets-jquery.csrf'
    end
    //= require jquery.csrf
  • Código fonte

    (function($) {
      $(document).ajaxSend(function(e, xhr, options) {
        var token = $('meta[name="csrf-token"]').attr('content');
        if (token) xhr.setRequestHeader('X-CSRF-Token', token);
      });
    })(jQuery);

raio de espada
fonte
No 5.1, usando o webpack, //= require jquery.csrfnão vai funcionar, certo ?. Em vez disso, usei o pacote js file import 'jquery.csrf'nele. Observe que você não precisa incluir isso com uma tag de pacote em suas visualizações.
Damien Justin Šutevski
3

Se você estiver usando javascript com jQuery para gerar o token no seu formulário, isso funcionará:

<input name="authenticity_token" 
       type="hidden" 
       value="<%= $('meta[name=csrf-token]').attr('content') %>" />

Obviamente, você precisa ter o <%= csrf_meta_tag %>no seu layout Ruby.

Tim Scollick
fonte
2

Para aqueles que precisam de uma resposta que não seja do jQuery, basta adicionar o seguinte:

xmlhttp.setRequestHeader ('X-CSRF-Token', $ ('meta [name = "csrf-token"]'). attr ('content'));

Um exemplo muito simples pode ser usado aqui:

xmlhttp.open ("POST", "example.html", true);
xmlhttp.setRequestHeader ('X-CSRF-Token', $ ('meta [name = "csrf-token"]'). attr ('content'));
xmlhttp.send ();
Mek
fonte
6
Isso não usa o jQuery para seletores?
Yule
2

Eu lutei com esse problema por dias. Qualquer chamada GET estava funcionando corretamente, mas todas as PUTs gerariam um erro "Não é possível verificar a autenticidade do token CSRF". Meu site estava funcionando bem até eu adicionar um certificado SSL ao nginx.

Eu finalmente tropecei nessa linha ausente nas minhas configurações de nginx:

location @puma { 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header Host $http_host; 
    proxy_redirect off;
    proxy_set_header X-Forwarded-Proto https;   # Needed to avoid 'WARNING: Can't verify CSRF token authenticity'
    proxy_pass http://puma; 
}

Após adicionar a linha ausente "proxy_set_header X-Forwarded-Proto https;", todos os meus erros de token CSRF são encerrados.

Espero que isso ajude alguém que também está batendo a cabeça contra uma parede. haha

Hoffmann
fonte
0

Estou usando o Rails 4.2.4 e não consegui entender por que estava recebendo:

Can't verify CSRF token authenticity

Eu tenho no layout:

<%= csrf_meta_tags %>

No controlador:

protect_from_forgery with: :exception

A chamada tcpdump -A -s 999 -i lo port 3000estava mostrando o cabeçalho sendo definido (apesar de não ser necessário definir os cabeçalhos com ajaxSetup- já foi feito):

X-CSRF-Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
DNT: 1
Content-Length: 125
authenticity_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

No final, estava falhando porque eu tinha os cookies desligados. O CSRF não funciona sem que os cookies sejam ativados, portanto, essa é outra causa possível se você estiver vendo esse erro.

Neil Stockbridge
fonte
é muito útil!
joehwang