Formularz wypełniony. Klikasz "Wyślij" i zamiast potwierdzenia dostajesz: "Token CSRF jest nieprawidłowy. Proszę spróbować wysłać formularz ponownie". Próbujesz drugi raz. Czasem działa. Czasem nie. Sam komunikat wygląda dość poważnie, ale nie oznacza, że ktoś właśnie włamuje się na stronę. Zwykle problem jest znacznie bardziej przyziemny - formularz ma stary token, wygasła sesja, przeglądarka nie przekazała potrzebnego cookie albo cache podał wersję strony, której już nie powinien podawać.
Co właściwie nie zgadza się z tokenem CSRF?
Wyobraź sobie zwykły formularz. Otwierasz go, wpisujesz dane i wysyłasz. Tyle widzisz.
W tle dzieje się trochę więcej.
Strona może wygenerować specjalny token powiązany z Twoją sesją. Nie musisz go przepisywać ani nawet wiedzieć, że istnieje. Formularz zabiera go ze sobą podczas wysyłania danych, a aplikacja sprawdza, czy wszystko się zgadza.
Jeżeli się zgadza - operacja idzie dalej.
Jeżeli tokenu nie ma, wygasł albo aplikacja spodziewa się już innego, żądanie zostaje zatrzymane. I właśnie wtedy pojawia się komunikat o nieprawidłowym tokenie CSRF.
Po co całe to zamieszanie?
CSRF to skrót od Cross-Site Request Forgery. Mechanizm ochronny ma utrudnić wykonanie operacji w imieniu zalogowanego użytkownika przez inną stronę. Przykładowo - jesteś zalogowany do pewnego serwisu, a odpowiednio przygotowana obca witryna próbuje wykorzystać Twoją aktywną sesję i wysłać do tego serwisu żądanie.
Token jest jednym ze sposobów sprawdzenia, czy żądanie rzeczywiście pochodzi z właściwego miejsca.
Dlatego komunikat o błędnym tokenie nie mówi: "wykryliśmy włamanie". Mówi raczej: "nie potrafimy potwierdzić tego żądania, więc go nie wykonamy".
Zanim zaczniesz szukać awarii - spróbuj jeszcze raz
Serio. Od tego warto zacząć.
Jeśli błąd wyskoczył jeden raz, odśwież stronę, ponownie otwórz formularz i spróbuj jeszcze raz. Nie ma sensu od razu logować się do serwera i zmieniać konfiguracji PHP.
Bardzo prosty scenariusz wygląda tak: otwierasz formularz o 10:00, zaczynasz go wypełniać, ktoś dzwoni. Potem kawa, inna karta w przeglądarce, kilka maili. Do formularza wracasz o 12:30 i dopiero wtedy klikasz "Wyślij".
Tymczasem sesja zdążyła wygasnąć.
Na ekranie nadal masz formularz wyglądający zupełnie normalnie. W środku siedzi jednak token wygenerowany kilka godzin wcześniej. Serwer już go nie chce.
Podobnie może być z formularzem pozostawionym w otwartej karcie przez noc.
Błąd pojawił się tylko raz? Odśwież stronę i pobierz świeżą wersję formularza. Jeśli po tym wszystko działa, nie ma większego sensu szukać skomplikowanej awarii.
Jeżeli odświeżenie nie pomaga, otwórz stronę w oknie prywatnym. Formularz nagle działa? To już jest jakiś trop. Warto sprawdzić cookies zapisane dla tej witryny, wylogować się i zalogować ponownie.
Nie trzeba przy tym od razu czyścić całej historii przeglądarki, wszystkich haseł i ciasteczek z ostatnich pięciu lat. Interesuje nas konkretna strona.
Błąd CSRF pojawia się za każdym razem
Jednorazowy błąd można zrzucić na wygasłą sesję. Dziesiątego z rzędu już raczej nie.
Jeżeli formularz za każdym razem kończy się tym samym komunikatem, coś po drodze nie działa tak, jak powinno. Token może być poprawnie tworzony, ale nie wracać do aplikacji. Może wracać, lecz aplikacja utraciła sesję, z którą był związany. Możliwe też, że użytkownik wcale nie dostaje świeżego formularza.
I tu zaczyna się prawdziwe szukanie.
Dobrze przypomnieć sobie, kiedy problem pojawił się po raz pierwszy. Wczoraj włączono cache? Strona została przeniesiona na inny hosting? Zmieniono domenę? Wymuszono HTTPS? Zaktualizowano CMS albo framework?
Jeżeli błąd zaczął się dokładnie po jednej z takich zmian, nie ignorowałbym tego zbiegu okoliczności.
Cache i CDN - tutaj często zaczyna się problem
Cache świetnie sprawdza się przy stronie, która dla każdego użytkownika wygląda tak samo. Artykuł, opis usługi, strona informacyjna - zapisujemy gotowy wynik i przy kolejnej wizycie nie trzeba budować go od początku.
Z formularzem zawierającym token związany z sesją sprawa nie zawsze jest taka prosta.
Wyobraź sobie, że system zapisuje w pamięci podręcznej cały HTML formularza razem z tokenem. Później zamiast wygenerować świeżą wersję, podaje użytkownikowi właśnie tę zapisaną kopię.
Formularz wygląda dobrze. Pola działają. Przycisk działa.
Dopiero po kliknięciu "Wyślij" wychodzi na jaw, że token nie pasuje do aktualnej sesji.
Dlatego przy powtarzającym się błędzie CSRF wyczyszczenie cache strony oraz CDN jest dobrym testem. Testem - nie rozwiązaniem na stałe.
Jeżeli po wyczyszczeniu formularz zaczyna działać, mamy konkretny kierunek. Trzeba sprawdzić zasady buforowania i wykluczyć miejsca, które nie powinny być traktowane jak zwykła statyczna podstrona.
Logowanie, koszyk, konto użytkownika, panel administracyjny czy formularze zależne od sesji to właśnie takie miejsca.
Czyszczenie cache codziennie rano nie jest naprawą.
Przeglądarka jest w porządku. Co sprawdzić dalej?
Jeśli błąd występuje u jednej osoby, można jeszcze podejrzewać jej przeglądarkę. Jeśli zgłaszają go wszyscy - Chrome, Firefox, telefon, komputer - dalsze kasowanie cookies przestaje mieć większy sens.
Trzeba spojrzeć na stronę od środka.
Najpierw sesja. Aplikacja wygenerowała token dla konkretnego użytkownika, więc przy wysyłaniu formularza musi nadal wiedzieć, z jaką sesją ma do czynienia. Jeśli pomiędzy wyświetleniem formularza a jego wysłaniem sesja znika albo zmienia identyfikator, prawidłowy wcześniej token może zostać odrzucony.
Potem cookies.
Problem potrafi pojawić się po zmianie adresu strony. Było example.pl, jest www.example.pl. Albo odwrotnie. Doszła subdomena. HTTP zostało zastąpione przez HTTPS. Sama strona działa i na pierwszy rzut oka wszystko wygląda poprawnie, ale ciasteczko sesyjne nie jest wysyłane tam, gdzie aplikacja się go spodziewa.
To samo dotyczy bardziej rozbudowanej infrastruktury. Proxy, load balancer, CDN czy kilka serwerów aplikacji mogą mieć znaczenie, jeżeli sesje nie są obsługiwane spójnie.
W tym momencie warto już zajrzeć do logów. Sam komunikat "Token CSRF jest nieprawidłowy" mówi jedynie, że weryfikacja się nie udała. Nie powie, czy przyczyną było wygaszenie sesji, brak cookie czy stary formularz podany z cache.
Logi mogą.
Wyłączenie CSRF naprawia formularz? To zły znak
Jest jeszcze rozwiązanie kuszące swoją skutecznością.
Wyłączyć sprawdzanie tokenu.
Formularz zaczyna działać. Błędu nie ma. Można uznać sprawę za zamkniętą.
Tylko że niczego nie naprawiliśmy. Usunęliśmy kontrolę, która wykrywała problem.
Przy zwykłym formularzu kontaktowym jest to zły pomysł. Przy operacjach wykonywanych po zalogowaniu - jeszcze gorszy. Zmiana danych użytkownika, hasła, adresu e-mail czy ustawień konta to właśnie miejsca, w których ochrona przed CSRF ma znaczenie.
Jeżeli po wyłączeniu zabezpieczenia wszystko zaczyna działać, potraktowałbym to raczej jako wskazówkę diagnostyczną: problem rzeczywiście jest związany z obsługą tokenu.
Teraz trzeba znaleźć dlaczego.
Czasami winny jest formularz trzymany zbyt długo w cache. Czasami sesja. Innym razem cookie po zmianie domeny albo konfiguracji HTTPS. Bywa też, że problem pojawia się dopiero po aktualizacji aplikacji.
Sam komunikat "Token CSRF jest nieprawidłowy" nie podaje więc gotowej diagnozy. Mówi tylko, w którym miejscu aplikacja powiedziała "stop".
I od tego miejsca najlepiej zacząć szukanie.

Komentarze