ActionController :: InvalidAuthenticityToken

148

Abaixo está um erro causado por um formulário no meu aplicativo Rails:

Processing UsersController#update (for **ip** at 2010-07-29 10:52:27) [PUT]
  Parameters: {"commit"=>"Update", "action"=>"update", "_method"=>"put", "authenticity_token"=>"ysiDvO5s7qhJQrnlSR2+f8jF1gxdB7T9I2ydxpRlSSk=", **more parameters**}

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

Isso acontece para cada não getsolicitação e, como você vê, authenticity_tokenexiste.

Nikita Rybak
fonte

Respostas:

207

Eu tive o mesmo problema, mas com páginas em cache. As páginas foram armazenadas em buffer com um token de autenticidade antigo e todas as ações usando os métodos post / put / delete foram reconhecidas como tentativas de falsificação. O erro (422 entidade não processável) foi retornado ao usuário.

A solução para o Rails 3:
Adicione:

 skip_before_filter :verify_authenticity_token  

ou como "sagivo" apontado no Rails 4, adicione:

 skip_before_action :verify_authenticity_token

Nas páginas que fazem cache.

Como o @toobulkeh comentou, isso não é uma vulnerabilidade :index, :showações, mas tenha cuidado ao usar isso :put, :postações.

Por exemplo:

 caches_page :index, :show  
 skip_before_filter :verify_authenticity_token, :only => [:index, :show]

Referência: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html

Nota adicionada por barlop- O Rails 4.2 descontinuou o skip_before_filter em favor do skip_before_action https://guides.rubyonrails.org/4_2_release_notes.html "A família de métodos * _filter foi removida da documentação. Seu uso é desencorajado em favor da * _action família de métodos "

Para o Rails 6 (como "collimarco" apontou), você pode usar skip_forgery_protectione que é seguro usá-lo para uma API REST que não usa dados da sessão.

Szymon Jeż
fonte
3
Provavelmente não é esse o caso, eu não conhecia caches_page antes da sua postagem. Mas vou verificar caches_page , obrigado.
Nikita Rybak
7
nos trilhos 4skip_before_action :verify_authenticity_token
Sagiv Ofek
88
Isso não é uma vulnerabilidade?
Quantumpotato
6
isso não é uma vulnerabilidade em :index, :showações. Mas tenha cuidado ao colocar isso em :put, :postações!
toobulkeh
14
embora eu concorde que às vezes você tenha um caso em que isso seja necessário (como talvez uma vez na vida), mas você precisa perceber que está corrigindo a segurança desativando a segurança. Não recomendado
equivalente8
77

Para mim, a causa desse problema no Rails 4 estava ausente,

<%= csrf_meta_tags %>

Linha no meu layout principal do aplicativo. Eu o excluí acidentalmente quando reescrevi meu layout.

Se não estiver no layout principal, será necessário em qualquer página em que você queira um token CSRF.

James McMahon
fonte
2
Também estamos recebendo esse erro. Mas é intermitente. Poderia ser esse o motivo ou isso não afetaria cada solicitação com erro?
Ryan-Neal Mes
@ Ryan-NealMes, se o seu modelo estiver faltando nessa linha, você receberá o erro. Portanto, é possível que alguns de seus modelos tenham e outros não.
James McMahon
1
@JamesMcMahon obrigado, eu descobri que meu caso é realmente causado por usuários limpando seus cookies ou bloqueando-os. Cargas aprendidas com esta pergunta!
Ryan-Neal Mes
61

Existem várias causas para esse erro (relacionadas ao Rails 4).

1. Verifique o <%= csrf_meta_tags %>presente no layout da página

2. verifique se o token de autenticidade está sendo enviado com chamadas AJAX se estiver usando o form_forhelper com a opção. remote: trueCaso contrário, você pode incluir a linha <%= hidden_field_tag :authenticity_token, form_authenticity_token %>dentro do bloco de formulários.

3. Se a solicitação estiver sendo enviada da página em cache, use o cache de fragmentos para excluir parte da página que envia a solicitação, por exemplo, button_toetc., caso contrário, o token ficará obsoleto / inválido.

Eu ficaria relutante em anular a proteção csrf ...

GoodViber
fonte
csrf_meta_tags deve estar em <head>? Como posso ter certeza de que não entra em conflito com os turbolinks?
Spark #
37

Basta adicionar o authenticity_tokenformulário in para corrigi-lo.

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Deepak Mahakale
fonte
3
Rails deveria enviar o token por padrão. Não queremos especificá-lo explicitamente. Sinto que o token mudou de alguma forma nesta situação aqui.
Abhi
1
No entanto, se você criou seu formulário sem ajuda, deve colocá-lo manualmente.
André Guimarães Sakata
30

O token de autenticidade é um valor aleatório gerado em sua exibição para provar que uma solicitação é enviada a partir de um formulário no seu site, e não em outro lugar. Isso protege contra ataques CSRF:

http://en.wikipedia.org/wiki/Cross-site_request_forgery

Verifique para ver quem é esse cliente / IP, parece que eles estão usando seu site sem carregar suas visualizações.

Se você precisar depurar mais, esta pergunta é um bom ponto de partida: Compreendendo o token de autenticidade do Rails

Editado para explicar: significa que eles estão chamando a ação para processar o envio do seu formulário sem nunca renderizá-lo no seu site. Isso pode ser malicioso (por exemplo, postar comentários de spam) ou pode indicar um cliente tentando usar sua API de serviço da web diretamente. Você é o único que pode responder isso pela natureza do seu produto e analisar suas solicitações.

Winfield
fonte
1
Obrigado, mas eu já sei o que é um token de autenticidade. Verifique quem é esse cliente / IP, parece que eles estão usando seu site sem carregar suas visualizações. Desculpe, o que significa "sem carregar visualizações"?
Nikita Rybak
1
Quero dizer que alguém (provavelmente um spammer) poderia enviar dados para o seu formulário sem passar pela interface do usuário do seu aplicativo. É possível fazer isso usando um programa de linha de comando como curl, por exemplo.
John Topley 29/07
John está exatamente certo. Isso significa que eles estão chamando a ação para processar o envio do seu formulário sem nunca renderizá-lo no seu site. Isso pode ser malicioso (por exemplo, postar comentários de spam) ou pode indicar um cliente tentando usar sua API de serviço da web diretamente. Você é o único que pode responder isso pela natureza do seu produto e analisar suas solicitações.
Winfield
Ok, eu não entendi o comentário de Winfield. Eu pensei que o aplicativo não estava de alguma forma configurado para 'carregar minhas visualizações' quando eu uso o navegador.
Nikita Rybak
1
Eu também tive outro pensamento, esses pedidos incluem um token, mas não é válido. Isso pode ser causado pelo cache da página que renderiza seu formulário ou por qualquer outra coisa que cause uma versão obsoleta do formulário.
Winfield
27

ActionController::InvalidAuthenticityTokentambém pode ser causado por um proxy reverso configurado incorretamente. Este é o caso, se no rastreamento da pilha, você obtiver uma linha parecida Request origin does not match request base_url.

Ao usar um proxy reverso (como nginx) como receptor para solicitação HTTPS e transmitir a solicitação não criptografada para o back-end (como o aplicativo Rails), o back-end (mais especificamente: Rack) espera alguns cabeçalhos com mais informações sobre a solicitação original do cliente para poder aplicar várias tarefas de processamento e medidas de segurança.

Mais detalhes estão disponíveis aqui: https://github.com/rails/rails/issues/22965 .

TL; DR: a solução é adicionar alguns cabeçalhos:

upstream myapp {
  server              unix:///path/to/puma.sock;
}

location / {
  proxy_pass        http://myapp;
  proxy_set_header  Host $host;
  proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header  X-Forwarded-Proto $scheme;
  proxy_set_header  X-Forwarded-Ssl on; # Optional
  proxy_set_header  X-Forwarded-Port $server_port;
  proxy_set_header  X-Forwarded-Host $host;
}
vmarquet
fonte
Uau, estou procurando por 3 horas uma solução para isso, e foi isso, obrigado!
evexoio
muito obrigado 6 horas tentando resolver isso no lado dos trilhos #
Joe Half Face
18

Tarde demais para responder, mas encontrei a solução.

Ao definir seu próprio formulário html, você perde a sequência de tokens de autenticação que deve ser enviada ao controlador por motivos de segurança. Mas quando você usa o auxiliar de formulário do rails para gerar um formulário, obtém algo como seguir

<form accept-charset="UTF-8" action="/login/signin" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="&#x2713;">
    <input name="authenticity_token" type="hidden" 
      value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
    .
    .
    .
  </div>
</form>

Portanto, a solução para o problema é adicionar o campo authenticity_token ou usar os auxiliares de formulário dos trilhos, em vez de remover, fazer o downgrade ou atualizar os trilhos.

amjad
fonte
9

Se você efetuou uma rake rails:updatealteração ou alterou recentemente o seu config/initializers/session_store.rb, isso pode ser um sintoma de cookies antigos no navegador. Espero que isso seja feito no dev / test (era para mim) e você pode limpar todos os cookies do navegador relacionados ao domínio em questão.

Se estiver em produção e você tiver alterado key, considere alterá-lo novamente para usar os cookies antigos (<- apenas especulação).

Kross
fonte
Sim! Para mim, ter um session_store.rb vazio estava causando o erro.
lafeber
6

Eu tive esse problema com chamadas javascript. Corrigi isso com a exigência de jquery_ujs no arquivo application.js.

Michael Koper
fonte
Sim, correto, eu também tive esse problema e adicionei jquery_ujs no aplicativo js. Funcionou.
Abhi
3

Tivemos o mesmo problema, mas percebemos que era apenas para solicitações usando http: // e não com https: //. A causa foi secure: truepara session_store:

Rails.application.config.session_store(
  :cookie_store,
  key: '_foo_session',
  domain: '.example.com',
  secure: true
)

Corrigido usando HTTPS ~ em todos os lugares :)

Darep
fonte
Encontrei isso ao usar rails s(não SSL) em vez do ponto de extremidade SSL que configurei para o desenvolvimento. Não foi até ler seu comentário que percebi o que estava fazendo. Depois que voltei a usar SSL, as coisas começaram a funcionar novamente. Obrigado!
19118 Karl Wilbur
1
Eu enfrentei esse problema no desenvolvimento. Em vez de secure: trueeu escrevisecure: !Rails.env.development?
murb
1

Para os trilhos 5, é melhor adicionar protect_from_forgery prepend: truedo que pular overify_authentication_token

aadeshere1
fonte
5
Por quê? Você poderia adicionar uma referência?
kwerle
1

Adicionar

//= require rails-ujs 

no

\app\assets\javascripts\application.js
Maicon Douglas
fonte
0

Eu tive esse problema e o motivo foi porque copiei e colei um controlador no meu aplicativo. Eu precisava mudar ApplicationControllerparaApplicationController::Base

user2954587
fonte
0

Eu tive o mesmo problema no localhost. Alterei o domínio do aplicativo, mas no arquivo de URLs e hosts ainda havia o domínio antigo. Atualizei o arquivo de favoritos e hosts do meu navegador para usar o novo domínio e agora tudo funciona bem.

MoD
fonte
0

Talvez você tenha a sua configuração NGINX para HTTPS, mas seus certificados são inválidos? Eu tive um problema semelhante no passado e o redirecionamento de http para https resolveu o problema

montrealmike
fonte
0

Verifiquei que <% = csrf_meta_tags%> está presente e a limpeza de cookies no navegador funcionou para mim.

Praveen KJ
fonte
0

Seguindo as recomendações do Chrome Lighthouse para uma carga mais rápida de aplicativos, assíncrono meu Javascript:

views/layout/application.html.erb

<%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload', async: true %>

Isso quebrou tudo e ocorreu o erro Token para meus formulários remotos. A remoção async: truecorrigiu o problema.

Maxence
fonte
0

Essa resposta é muito mais específica para o Ruby on Rails, mas espero que ajude alguém.

Você precisa incluir o token CSRF em todas as solicitações não GET. Se você está acostumado a usar o JQuery, o Rails possui uma biblioteca auxiliar chamada jquery-ujsque é construída sobre ela e adiciona algumas funcionalidades ocultas. Uma das coisas que ele faz é incluir automaticamente o token CSRF em todas as ajaxsolicitações. Veja aqui .

Se você se afastar dele como eu, você pode se deparar com um erro. Você pode simplesmente enviar o token manualmente ou usar outra biblioteca para ajudar a raspar o token do DOM. Veja este post para mais detalhes.

user2490003
fonte
0

Para o ambiente de desenvolvimento, tentei muitas dessas tentativas para corrigir esse problema, no Rails 6. Nenhuma delas ajudou. Portanto, se nenhuma dessas sugestões funcionou para você, tente abaixo.

A única solução que encontrei foi adicionar um arquivo txt à sua pasta / tmp.

No diretório raiz do seu aplicativo, execute:

touch tmp/caching-dev.txt

Ou crie manualmente um arquivo com esse nome na sua pasta / tmp. Como isso foi corrigido para mim, presumo que a raiz do problema seja um conflito de cache.

Twistedben
fonte
-1

No trilhos 5, precisamos adicionar 2 linhas de código

    skip_before_action :verify_authenticity_token
    protect_from_forgery prepend: true, with: :exception
giapnh
fonte
-2

Instalando

gem 'remotipart' 

pode ajudar

Alexei.B
fonte
3
embora isso possa ser a resposta, mas também é útil incluir a parte essencial da resposta e explicar por que / como ela funciona.
Roy Lee
-15

Problema resolvido ao fazer o downgrade para 2.3.5 de 2.3.8. (além da infame questão "Você está sendo redirecionado".)

Nikita Rybak
fonte
@ Flip talvez seja uma idéia para atualizar a resposta aceita?
lafeber 4/06