2017-01-05 34 views
6

Nasze dzienniki błędów zawierają sporadycznie przesyłanie prawidłowych formularzy, które powodują błędy ActionController::InvalidAuthenticityToken.Jak to jest możliwe, aby prawowity użytkownik przesłał nieprawidłowy token CSRF w Railsach?

Moja hipoteza jest taka, że ​​token CSRF przechowywany w pliku cookie sesji użytkownika zmienił się w pewnym momencie po załadowaniu formularza, ale przed jego przesłaniem. Powoduje to niezgodność między tokenem POSTed i tokenem w pliku cookie, co prowadzi do tego błędu.

Biorąc pod uwagę, że plik cookie sesji Rails wygasa dopiero po zakończeniu sesji przeglądania (tj. Po zamknięciu przeglądarki), w jaki sposób można zmienić ten plik cookie (i token CSRF) bez zamykania przeglądarki ?

Używamy plików cookie do przechowywania danych sesji, co jest domyślnym zachowaniem Railsów.

Odpowiedz

0

Oto co wiemy:

  • Uzasadnione zgłaszanie formularzy, które powodują InvalidAuthenticityToken wyjątek jakoś stracił swój pierwotny CSRF token.
  • Token jest przechowywany w sesji, która jest przechowywana w zaszyfrowanym pliku cookie. Więc ten błąd oznacza, że ​​plik cookie sesji zmienił się od czasu wygenerowania formularza.
  • Plik cookie sesji nie wygasa, chyba że okno przeglądarki użytkownika zostanie zamknięte.

Sądzę, że istnieją dwa sposoby, aby nieważne tokeny CSRF mogły zostać przesłane przez uprawnionych użytkowników.

Należy zwrócić uwagę, że odnoszą się one w szczególności do szyn 4.2. Jak rozumiem, "żetony CSRF w formie" w Railsach 5 mogą je złagodzić.

1. zmiana Sesja na innej karcie

Zgodnie @crazymykl's answer, użytkownik może otworzyć formularz, a następnie zalogować się na innej karcie. Spowodowałoby to zmianę pliku cookie sesji przechowywanego w przeglądarce użytkownika. Po powrocie do oryginalnej karty i przesłaniu formularza token z formularza nie pasował do tokena w sesji, a błąd pojawił się.

2. Buforowanie

Zgodnie this rails bug, Safari zachowuje się dziwnie z buforowania w pewnych okolicznościach. Mówiąc, aby ponownie otworzyć te same okna, co ostatnio (przez Safari > Preferences > General), otwierając formularz i kończąc działanie Safari w formularzu, który jest wyświetlany ponownie.

Przesłanie tego buforowanego formularza powoduje błąd CSRF. Jak podsumowuje błąd, wygląda na to, że Safari buforuje stronę, ale zrzuca plik cookie sesji. Stąd niedopasowanie.

Rozwiązaniem tego problemu jest ustawienie nagłówka Cache-Control za pomocą dyrektywy no-store. (Różnica między no-cache i no-store wyjaśniona here).

Dalsze przykłady mile widziane :).

0

Jeśli zamykanie przeglądarki nie jest opcją. Następnie musisz wylogować użytkownika. Aby to osiągnąć, należy wprowadzić następujący kod w aplikacji ApplicationController.

rescue_from ActionController :: InvalidAuthenticityToken do | exception |

sign_out_user # Przykład metoda, która zniszczy cookie użytkowników

koniec

P.S: Powyżej jest od http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf więc odwołać się, że aby uzyskać więcej informacji.

+0

dzięki. Dana ścieżka dotyczy tylko uwierzytelnionych użytkowników, więc nie sądzę, że wylogowali się przed wyjątkiem CSRF. – djb

+0

Prawda. Więc kiedy CSRF zostanie zmieniony z nieznanych przyczyn. Zostały wylogowane. Czy możesz wykluczyć, że użytkownicy w tym przypadku celowo edytują CSRF? –

+0

Nie z absolutną pewnością, ale jest to bardzo mało prawdopodobne. Czy twoim zdaniem nie ma innego sposobu, aby token kiedykolwiek stał się nieważny? – djb

7

Użytkownik mógł się wylogować i ponownie zalogować, ale miał zakładkę z formularzem otwartym ze starej sesji. To by wysłało stary token.

+0

Cześć, dziękuję za tę odpowiedź. Czy jest jakaś inna możliwość? – djb

0

Czy używasz formularza Ajax do przesłania zapytania? Czy twoja strona ma wiele formularzy? Jeśli tak, sprawdź swój kod, czy prawidłowy token csrf został przesłany wraz z wnioskiem. Mieliśmy podobny problem, że strona jest renderowana za pomocą jednego tokenu csrf i użyliśmy tego tokena do przesłania formularza 1, a otrzymalibyśmy kolejny token csrf, ale drugi wysłał stary token csrf, który spowodował błąd. nie jestem pewien, jak to jest pomocne, ale chcesz podzielić się z podobnym problemem borykają się mną

+0

Dzięki za odpowiedź! Nie, oboje, przepraszam. – djb

1

Napisałeś: Biorąc pod uwagę, że Rails cookie sesji wygasa dopiero po zakończeniu sesji przeglądania (czyli gdy przeglądarka jest zamknięta), jakie są w jaki sposób można zmienić to ciasteczko (i token CSRF) bez zamykania przeglądarki?


Po pierwsze, twoja hipoteza jest ważna. Jednak sposób, w jaki tam dotarłeś, może być warty rozważenia.

Przedstawione domniemanie wymaga dwóch poziomów.

Po pierwsze: przechowywany plik cookie nie zostaje usunięty po zakończeniu sesji przeglądania, chyba że coś zostało zakodowane w ten sposób; plik cookie jest prawdopodobnie trwały do ​​czasu przekroczenia limitu czasu cookie, więc prawdopodobnie następny dostęp do strony będzie korzystał ze starego tokena, ale ponieważ programiści zazwyczaj pozwalają na "nowe logowanie" w celu odświeżenia strony, prawdopodobnie odświeżą token na ten czas. Zobacz odpowiedź @ Shikhar-Mann, aby lepiej zrozumieć sign_out_user.

Po drugie: plik cookie nie musi być zmieniany dla tego problemu, jest to niedopasowanie tokenu CSRF, który jest problemem.

Pytanie podstawowe powinno brzmieć: jakie są sposoby na to, że możemy mieć niedopasowany token CSRF, na który łatwiej byłoby odpowiedzieć: stare dane na kliencie z powodu długiego oczekiwania, co powoduje przekroczenie limitu czasu na serwerze, co unieważnia token CSRF podczas opóźnienia. Jeśli strona internetowa nie jest skonfigurowana/utworzona, aby również limitu czasu i przekierowania, klient/użytkownik nigdy by się nie dowiedział.

Czy mogę również zasugerować, że CSRF NIE będzie trwał? Naprawdę nie jest to wartościowe, jeśli możesz uzyskać dostęp do danych formularza; zwykle tworzę ukryte pole z danymi CSRF i używam go, aby zamiast tego przesłać ponownie. CSRF nie żyje bardzo długo, a dane sesji są utrzymywane.

+0

Dziękuję za tę szczegółową odpowiedź. Wydaje się, że token CSRF nie może wygasnąć z powodu upływu czasu, ponieważ jest skonfigurowany do wygasania dopiero pod koniec sesji. – djb

+0

To nie tak działa CSRF. Wygasa po określonym czasie, ponieważ serwer wygaśnie - na końcu sesji po stronie serwera. –

+0

Możesz mieć rację! W Railsach sesja jest przechowywana w pliku cookie, a nie na serwerze. – djb