ActionController :: InvalidAuthenticityToken

148

Poniżej znajduje się błąd spowodowany przez formularz w mojej aplikacji 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):

Dzieje się tak w przypadku każdego getwniosku, który authenticity_tokennie jest żądany i, jak widzisz, istnieje.

Nikita Rybak
źródło

Odpowiedzi:

207

Miałem ten sam problem, ale ze stronami, które były buforowane. Strony były buforowane nieaktualnym tokenem autentyczności, a wszystkie akcje przy użyciu metod post / put / delete, gdzie rozpoznano próby fałszerstwa. Użytkownik zwrócił błąd (422 Unprocessable Entity).

Rozwiązanie dla Rails 3:
Dodaj:

 skip_before_filter :verify_authenticity_token  

lub jak "sagivo" wskazano w Rails 4 dodaj:

 skip_before_action :verify_authenticity_token

Na stronach obsługujących buforowanie.

Jak @toobulkeh skomentował to nie jest luka na :index, :showdziałań, ale uważaj na ten użyciem :put, :postdziałań.

Na przykład:

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

Źródła: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html

Uwaga dodana przez barlop- Rails 4.2 przestarzałe skip_before_filter na rzecz skip_before_action https://guides.rubyonrails.org/4_2_release_notes.html "Rodzina metod * _filter została usunięta z dokumentacji. Odradza się ich używanie na rzecz * _action rodzina metod "

W przypadku Rails 6 (jak wskazał "collimarco") możesz go używać skip_forgery_protectioni że jest to bezpieczne w przypadku REST API, które nie używa danych sesji.

Szymon Jeż
źródło
3
To mało prawdopodobne, nie wiedziałem o caches_page przed Twoim postem. Ale sprawdzę caches_page , dzięki.
Nikita Rybak
7
w szynach 4skip_before_action :verify_authenticity_token
Sagiv Ofek
88
Czy to nie jest luka?
quantumpotato
6
nie jest to luka w :index, :showdziałaniach. Ale uważaj, aby to zrobić :put, :post!
toobulkeh
14
chociaż zgadzam się, że czasami zdarza się, że jest to potrzebne (na przykład raz w życiu), ale musisz zdać sobie sprawę, że naprawiasz bezpieczeństwo, wyłączając zabezpieczenia. Niezalecane
odpowiednik 8
77

Dla mnie przyczyną tego problemu w Rails 4 był brak,

<%= csrf_meta_tags %>

Linia w moim głównym układzie aplikacji. Przypadkowo usunąłem go, przepisując mój układ.

Jeśli tego nie ma w głównym układzie, będziesz go potrzebować na dowolnej stronie, na której chcesz umieścić token CSRF.

James McMahon
źródło
2
Otrzymujemy również ten błąd. Ale to przerywane. Czy to może być powód, czy też nie wpłynęłoby to na każde żądanie z błędem?
Ryan-Neal Mes
@ Ryan-NealMes, jeśli w Twoim szablonie brakuje tej linii, otrzymasz błąd. Jest więc możliwe, że niektóre z Twoich szablonów go mają, a inne nie.
James McMahon
1
@JamesMcMahon dzięki, zorientowałem się, że mój przypadek jest w rzeczywistości spowodowany przez użytkowników, którzy usuwają pliki cookie lub mają zablokowane pliki cookie. Nauczyłem się wielu rzeczy z tego pytania!
Ryan-Neal Mes
61

Istnieje kilka przyczyn tego błędu (dotyczy to Rails 4).

1. Sprawdź, czy jest <%= csrf_meta_tags %>obecny w układzie strony.

2. Sprawdź, czy token autentyczności jest wysyłany z wywołaniami AJAX, jeśli używasz form_forpomocnika z remote: trueopcją. Jeśli nie, możesz dołączyć linię <%= hidden_field_tag :authenticity_token, form_authenticity_token %>do bloku formularza.

3. Jeśli żądanie jest wysyłane ze strony buforowanej, użyj buforowania fragmentów, aby wykluczyć część strony, która wysyła żądanie, np. button_toItp. W przeciwnym razie token będzie nieaktualny / nieprawidłowy.

Nie chciałbym anulować ochrony CSRF ...

GoodViber
źródło
csrf_meta_tags powinno znajdować się w <head>? Jak mogę się upewnić, że nie koliduje z turbolinkami?
sparkle
37

Samo dodanie authenticity_tokenformularza naprawiło to za mnie.

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Deepak Mahakale
źródło
3
Railsy powinny domyślnie wysyłać token. Nie chcemy tego wprost określać. Czuję, że w tej sytuacji token jest jakoś zmieniony.
Abhi
1
Jeśli jednak zbudowałeś swój formularz nie używając pomocników, powinieneś umieścić go ręcznie.
André Guimarães Sakata
30

Token autentyczności to losowa wartość generowana w Twoim widoku, aby udowodnić, że żądanie zostało przesłane z formularza w Twojej witrynie, a nie gdzie indziej. Chroni to przed atakami CSRF:

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

Sprawdź, kim jest ten klient / adres IP, wygląda na to, że korzysta z Twojej witryny bez ładowania Twoich widoków.

Jeśli chcesz dalej debugować, to pytanie jest dobrym miejscem do rozpoczęcia: Zrozumienie tokenu autentyczności Rails

Zredagowano w celu wyjaśnienia: oznacza to, że wywołują akcję przetwarzania przesłania formularza bez renderowania formularza w witrynie. Może to być złośliwe (na przykład publikowanie komentarzy spamowych) lub może wskazywać, że klient próbuje bezpośrednio korzystać z interfejsu API usługi sieciowej. Tylko Ty możesz odpowiedzieć na to pytanie ze względu na charakter Twojego produktu i analizę Twoich żądań.

Winfield
źródło
1
Dzięki, ale już wiem, co to jest token autentyczności. Sprawdź, kim jest ten klient / adres IP, wygląda na to, że korzysta z Twojej witryny bez ładowania Twoich widoków. Przepraszam, co oznacza „bez ładowania widoków”?
Nikita Rybak
1
Oznacza to, że ktoś (prawdopodobnie spamer) może przesyłać dane do formularza bez przechodzenia przez interfejs użytkownika aplikacji. Można to zrobić na przykład za pomocą programu wiersza poleceń, takiego jak curl.
John Topley,
John ma rację. Oznacza to, że wywołują akcję przetwarzania przesłanego formularza bez renderowania formularza w witrynie. Może to być złośliwe (na przykład publikowanie komentarzy spamowych) lub może wskazywać, że klient próbuje bezpośrednio korzystać z interfejsu API usługi sieciowej. Tylko Ty możesz odpowiedzieć na to pytanie ze względu na charakter Twojego produktu i analizę Twoich żądań.
Winfield
Ok, źle zrozumiałem komentarz Winfielda. Myślałem, że aplikacja nie została w jakiś sposób skonfigurowana do „ładowania moich widoków”, gdy używam przeglądarki.
Nikita Rybak
1
Miałem też inną myśl, te żądania zawierają token, ale nie jest ważny. Może to być spowodowane buforowaniem strony wyświetlającej formularz lub czymś innym, co może potencjalnie powodować przestarzałą wersję formularza.
Winfield
26

ActionController::InvalidAuthenticityTokenmoże być również spowodowany błędną konfiguracją zwrotnego serwera proxy. Dzieje się tak, jeśli w śladzie stosu pojawi się linia wyglądająca jak Request origin does not match request base_url.

Podczas korzystania z odwrotnego proxy (takiego jak nginx) jako odbiornika dla żądania HTTPS i przesyłania żądania w postaci niezaszyfrowanej do zaplecza (takiego jak aplikacja Rails), zaplecze (dokładniej: Rack) oczekuje niektórych nagłówków z większą ilością informacji o pierwotnym żądaniu klienta aby móc stosować różne zadania przetwarzania i środki bezpieczeństwa.

Więcej szczegółów można znaleźć tutaj: https://github.com/rails/rails/issues/22965 .

TL; DR: rozwiązaniem jest dodanie kilku nagłówków:

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
źródło
Wow, szukałem rozwiązania tego problemu przez 3 godziny i to było to, dzięki!
evexoio,
dziękuję bardzo za 6 godzin prób rozwiązania tego problemu po stronie torów
Joe Half Face
18

za późno na odpowiedź, ale znalazłem rozwiązanie.

Definiując swój własny formularz html, brakuje ciągu tokena uwierzytelniania, który powinien zostać wysłany do kontrolera ze względów bezpieczeństwa. Ale kiedy używasz helpera formularza rails do generowania formularza, otrzymujesz coś w rodzaju śledzenia

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

Więc rozwiązaniem problemu jest albo dodanie pola authentication_token, albo użycie pomocników formularza rails zamiast usuwania, obniżania lub modernizacji szyn.

amjad
źródło
9

Jeśli zrobiłeś rake rails:updatelub niedawno zmieniłeś swoje config/initializers/session_store.rb, może to być objaw starych plików cookie w przeglądarce. Mam nadzieję, że odbywa się to na etapie tworzenia / testowania (to było dla mnie) i możesz po prostu wyczyścić wszystkie pliki cookie przeglądarki związane z daną domeną.

Jeśli to jest w produkcji i zostało zmienione key, rozważ zmianę z powrotem na używanie starych plików cookie (<- tylko spekulacje).

kross
źródło
Tak! Dla mnie błąd powodował posiadanie pustego pliku session_store.rb.
lafeber
6

Miałem ten problem z połączeniami javascript. Naprawiłem to, wymagając tylko jquery_ujs w pliku application.js.

Michael Koper
źródło
Tak, zgadza się, też miałem ten problem i dodałem jquery_ujs w aplikacji js. Zadziałało.
Abhi
3

Mieliśmy ten sam problem, ale zauważyliśmy, że dotyczy to tylko żądań używających http: //, a nie https: //. Przyczyną była secure: truesesja_store:

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

Naprawiono przy użyciu HTTPS ~ wszędzie :)

Darep
źródło
Napotkałem to podczas używania rails s(bez SSL) zamiast punktu końcowego SSL, który skonfigurowałem do programowania. Dopiero gdy przeczytałem twój komentarz, zdałem sobie sprawę, co robię. Gdy wróciłem do korzystania z SSL, wszystko zaczęło działać ponownie. Dzięki!
Karl Wilbur
1
Miałem do czynienia z tym problemem w trakcie opracowywania. Zamiast secure: truepisaćsecure: !Rails.env.development?
murb
1

W przypadku szyn 5 lepiej dodać protect_from_forgery prepend: trueniż pominąćverify_authentication_token

aadeshere1
źródło
5
Czemu? Czy możesz dodać odniesienie?
kwerle
1

Dodaj

//= require rails-ujs 

w

\app\assets\javascripts\application.js
Maicon Douglas
źródło
0

Miałem ten problem, a powodem było to, że skopiowałem i wkleiłem kontroler do mojej aplikacji. Musiałem zmienić ApplicationControllernaApplicationController::Base

user2954587
źródło
0

Miałem ten sam problem na hoście lokalnym. Zmieniłem domenę aplikacji, ale w adresach URL i pliku hostów nadal była stara domena. Zaktualizowałem moje zakładki przeglądarki i plik hostów, aby używać nowej domeny i teraz wszystko działa dobrze.

MoD
źródło
0

Może masz konfigurację NGINX dla HTTPS, ale Twoje certyfikaty są nieważne? W przeszłości miałem podobny problem i przekierowanie z http na https rozwiązało problem

montrealmike
źródło
0

Sprawdziłem, czy <% = csrf_meta_tags%> są obecne i wyczyszczenie plików cookie w przeglądarce zadziałało.

Praveen KJ
źródło
0

Zgodnie z zaleceniami Chrome Lighthouse dotyczącymi szybszego ładowania aplikacji, zsynchronizowałem mój JavaScript:

views/layout/application.html.erb

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

To zepsuło wszystko i spowodowało błąd tokena dla moich zdalnych formularzy. Usunięcie async: truerozwiązało problem.

Maxence
źródło
0

Ta odpowiedź jest znacznie bardziej specyficzna dla Ruby on Rails, ale miejmy nadzieję, że komuś pomoże.

Musisz dołączyć token CSRF do każdego żądania innego niż GET. Jeśli jesteś przyzwyczajony do używania JQuery, Railsy mają bibliotekę pomocniczą o nazwie, jquery-ujsktóra buduje się na niej i dodaje pewne ukryte funkcje. Jedną z rzeczy, które robi, jest automatyczne dołączanie tokenu CSRF do każdego ajaxżądania. Zobacz tutaj .

Jeśli odejdziesz od tego tak, jak ja, możesz znaleźć się z błędem. Możesz po prostu przesłać token ręcznie lub użyć innej biblioteki, aby pomóc wydobyć token z DOM. Więcej szczegółów znajdziesz w tym poście .

user2490003
źródło
-1

W railsach 5 musimy dodać 2 linie kodu

    skip_before_action :verify_authenticity_token
    protect_from_forgery prepend: true, with: :exception
giapnh
źródło
-2

Instalowanie

gem 'remotipart' 

może pomóc

Alexei.B
źródło
3
chociaż może to być odpowiedź, ale pomocne jest również uwzględnienie zasadniczej części odpowiedzi i wyjaśnienie, dlaczego / jak to działa.
Roy Lee
-15

Problem rozwiązany przez obniżenie wersji do 2.3.5 z 2.3.8. (a także niesławny problem „Jesteś przekierowywany”)

Nikita Rybak
źródło
@Flip Może to pomysł, aby zaktualizować zaakceptowaną odpowiedź?
lafeber