2015-01-14 15 views
9

Mieliśmy ten problem na naszej stronie, że otrzymaliśmy błędy CSRF losowo od naszych użytkowników. Sesyjne pliki cookie i dane sesji zostały ustawione na wygasłe w ciągu 12 godzin, a sterownik sesji jest ustawiony na korzystanie z usługi Redis. Po przeprowadzeniu naszych dochodzeń udało nam się w końcu zasymulować warunki wyjątku. Oto scenariusz:Sesja Laravel wygasa losowo

Użytkownik otwiera dwie różne strony w witrynie, używając przeglądarki Chrome z opcją "otwórz ostatnio zamknięte karty". Jedna ze stron ma na niej postać (np. Login), a następnie użytkownik opuszcza przeglądarkę w pewnym momencie. Ponownie otworzył swoją przeglądarkę następnego dnia (minęło 12 godzin, więc sesyjne pliki cookie i dane sesji wygasły) Chrome próbuje ponownie załadować wszystkie otwarte strony. Wysyła dwa jednoczesne żądania do serwera, podczas gdy żaden z nich nie ma pliku cookie sesji. Po zakończeniu serwera Laravel generuje dla każdego z dwóch różnych identyfikatorów sesji. Chrome odbiera je i zastępuje jeden na drugim pliku cookie sesji. Gdy użytkownik spróbuje przesłać formularz (np. Login), generuje błąd CSRF, ponieważ ciasteczko sesji formularza jest nadpisywane.

Mieliśmy również kilka żądań postów AJAX, które dostaliśmy błędy CSRF z powodu tego warunku.

Zastanawiałem się, czy Laravel może generować ten sam identyfikator sesji dla obu wniosków w bezpieczny sposób.

Czy ktoś ma pomysły, jak możemy rozwiązać ten problem?

PS: używamy laravel 4.1 przy tej konfiguracji sesji:

return array(

    'driver' => 'redis', 

    'lifetime' => 720, 

    'expire_on_close' => false, 

    'files' => storage_path().'/sessions', 

    'connection' => null, 

    'table' => 'sessions', 

    'lottery' => array(2, 100), 

    'cookie' => 'laravel_session', 

    'path' => '/', 

    'domain' => '.ourdomain.com', 
); 
+0

Może to być pomocne http://stackoverflow.com/questions/27938186/ laravel-only-allow-one-session-per-user-at-time – astroanu

+0

@astro to po prostu usuwa ostatnią sesję, która powoduje ten sam problem. jakiś pomysł na generowanie tego samego identyfikatora sesji w bezpieczny sposób? – Amir

+0

Zgaduję, że jedyną metodą byłoby rozszerzenie klasy sesji i napisanie własnego? http://laravel.com/docs/4.2/extending#session – astroanu

Odpowiedz

11

Po wielu dochodzenia w sprawie, w naszej firmie, doszedłem do tego wyniku, mam nadzieję, że to pomaga, przede wszystkim tutaj jest nasze wymagania środowiskowe:

  • PHP: 5.3.3
  • laravel: 4,1
  • OS: CentOS 6 na serwerze i OS X Mavericks w środowisku programistycznym
  • APACHE 2
  • mysql 05.06.19
  • REDIS: 2.4.10
  • PREDIS. 0,8 *

pierwsze wydaje się, że wyjątek TokenMistmatch występuje zróżnicowane inaczej warunki, prawie zbadałem ich wszystkich i byłem w stanie rozwiązać niektóre z nich, niektóre zależą od logiki stojącej za sesją, a niektóre mogą być błędami. Poniżej wyjaśnię każdą sytuację, z którą się spotkałem.

1. Przeterminowane sesje

Powiedzmy skonfigurowaniu sesji przez 3 godziny użytkownik otwiera formularz iz jakiegoś powodu zostawia komputer (coraz filiżankę kawy), więc po 3 godzinach, gdy sesja wygasła, próbuje przesłać formularz i otrzymuje wyjątek od tokena. właśnie dlatego wszyscy raz na jakiś czas otrzymują błąd symboliczny, niezależnie od tego, na ile stabilna jest ta aplikacja, mogę sobie wyobrazić 2 sposoby, aby temu zapobiec i odnawiają plik cookie sesji przy użyciu ajaxa w odpowiednim czasie lub wydłużają czas wygaśnięcia sesji przez znaczną ilość czasu.

2.Zgłoszenia współbieżne w przypadku wygaśnięcia sesji

Czasami na ładowanie pierwszej strony przychodzą równoczesne żądania, na przykład użytkownik ma dwie różne karty otwarte na chromie i po ponownym otwarciu chrome chrome wysyła żądania jednocześnie lub możesz mieć wiele współbieżnych wniosek ajax na ładunek pierwszej strony aplikacji. więc pamiętaj, że plik cookie sesji jest odbierany po otrzymaniu pierwszej odpowiedzi, ale możesz wysłać następne żądanie, zanim to się stanie, a zatem otrzymasz nową sesję (nowy plik cookie) na każde żądanie, co może doprowadzić do wyjątku tokena, jeśli któryś z tych wnioski wypełnia formularz. możesz zapobiec temu scenariuszowi w oparciu o jego źródło, na przykład jeśli zapytanie ajax powoduje problem i nie używasz sesji w odpowiedziach ajaxowych, możesz wyłączyć wysyłanie pliku cookie sesji, jeśli żądanie jest ajaxowe, w drugim scenariuszu (klikając przesłać przycisk kilka razy) można łatwo wyłączyć przycisk po jego przesłaniu.

3. jednoczesnych żądań przy logowaniu

Gdy nastąpiło logowanie, laravel ze względów bezpieczeństwa zmienia identyfikator sesji, skopiuj dane sesji i niszczy ostatniej sesji tak powiedzmy z jakiegoś powodu po zalogowaniu jednoczesnych żądań stało się (kilkakrotne kliknięcie przycisku logowania), aby identyfikator sesji był wielokrotnie odtwarzany i ZNISZCZA ostatnie wygenerowane sesje po stronie serwera, ponieważ niektóre z tych żądań nadal używają wcześniejszego identyfikatora sesji (który już nie istnieje po stronie serwera)) prowadzi to do regeneracji tokenu CSRF, pamiętaj, że zwykle laravel nie regeneruje tokena przy logowaniu, jeśli może znaleźć token w sesji gościa (niezalogowanej), ale w tym przypadku jako gue st sesja jest niszczona, w wyniku czego zregeneruje token i może doprowadzić do wyjątku tokena w innych żądaniach, które używają oryginalnego tokena. należy również zauważyć, że nie tylko ten problem może powodować wyjątek tokenowy, ale może również spowodować wylogowanie użytkownika po jednym żądaniu, ponieważ żądania równoczesne mogą zmienić zalogowaną sesję. I rozwiązać ten problem poprzez zmianę jednego wiersza w kodzie laravel w Illuminate\Auth\Guard:updateSession:

protected function updateSession($id) 
{ 
     $this->session->put($this->getName(), $id); 

     //$this->session->migrate(true); 
     $this->session->migrate() 
} 

przechodząc wierny metodzie migrować sklepu sesji spowoduje zniszczenie sesji na serwerze po migracji, więc teraz dane będą pozostaną na serwerze i zostaną zniszczone w czasie ich wygaśnięcia, a nie na tej prośbie, a rozwiąże to problem. Nie wiem, czy możemy to nazwać błędem w laravel, ale myślę, że możemy wymyślić lepsze rozwiązanie.

4. Przeglądarki

Po zbadaniu dzienniki okazało się, że niektóre z tych tokenów wyjątkami były z powodu przeglądarka użytkownika nie zaakceptowaniem cookie sesji, widziałem go najbardziej na iOS Safari, wierzę, że to coś, czego nie możemy z tym zrobić.

5. Redis bug

Niektóre z wyjątków tokenów na naszej sever z powodu REDiS jakiegoś powodu laravel nie mógł odczytać dane sesji z serwera Redis po otwarciu sesji więc byłoby doprowadzić do regeneracja tokenu CSRF. działo się to przypadkowo na naszym serwerze, więc próbowałem zmienić sterownik sesji i ten typ wyjątków zniknął. Próbowałem sterowników baz danych, apc i plików i żaden nie spowodował tego problemu. Nie znalazłem jeszcze przyczyny błędu, ale myślę, że może to być błąd z redis lub biblioteką predis. (jak wiesz, laravel 4.1 nie używa najnowszej wersji predis z powodu problemów ze zgodnością).

Okej, to są moje doświadczenia z ostatnich dwóch miesięcy pracy nad tym problemem.Mam nadzieję, że może to zmienić Twój punkt widzenia dotyczący rozwiązania tego problemu, najważniejsze jest to, że wyjątek tokena nie występuje z jednego powodu, że może być wynikiem wielu problemów. proszę, podziel się ze mną, jeśli miałeś podobny incydent lub masz coś nowego.

+0

@ Amire Hi, czy znalazłeś lepsze rozwiązanie dla scenariusza 1? –

+0

@shangyeshen Niestety nie, ostatecznie zwiększyliśmy czas wygaśnięcia sesji. – Amir

0

Natknąłem się na tę kwestię w różnych momentach, bez konkretnego powodu, i nie zostało to wspomniane przez Amira.

Czyszczenie plików cookie domeny działa dla scenariusza, który widzę.

0

W moim przypadku był to problem z buforowanym plikiem konfiguracyjnym. Laravel tworzy plik konfiguracyjny, który jest buforowany w folderze bootstrap/cache. Zmień nazwę tego pliku config.php na coś innego i metę „php rzemieślnik cache: clear”

następnie uruchomić witrynę i powinien działać dobrze