Próbuję zrozumieć cały problem z CSRF i odpowiednie sposoby, aby temu zapobiec. (Zasoby, które przeczytałem, zrozumiałem i zgadzam się z: Arkuszem zapobiegania OWASP CSRF , Pytania dotyczące CSRF .)
Jak rozumiem, luka wokół CSRF wynika z założenia, że (z punktu widzenia serwera) prawidłowy plik cookie sesji w przychodzącym żądaniu HTTP odzwierciedla życzenia uwierzytelnionego użytkownika. Ale wszystkie pliki cookie dla domeny pochodzenia są magicznie dołączone do żądania przez przeglądarkę, więc tak naprawdę cały serwer może wnioskować z obecności prawidłowego pliku cookie sesji w żądaniu, że żądanie pochodzi z przeglądarki, która ma uwierzytelnioną sesję; nie może dalej zakładać niczego o kodziedziałający w tej przeglądarce lub czy rzeczywiście odzwierciedla życzenia użytkowników. Aby temu zapobiec, należy dołączyć do żądania dodatkowe informacje uwierzytelniające („token CSRF”), przenoszone w inny sposób niż automatyczna obsługa plików cookie w przeglądarce. Mówiąc luźniej, plik cookie sesji uwierzytelnia użytkownika / przeglądarkę, a token CSRF uwierzytelnia kod działający w przeglądarce.
Krótko mówiąc, jeśli używasz sesyjnego pliku cookie do uwierzytelniania użytkowników swojej aplikacji internetowej, powinieneś również dodać token CSRF do każdej odpowiedzi i wymagać pasującego tokenu CSRF w każdym (mutującym) żądaniu. Token CSRF wykonuje następnie objazd z serwera do przeglądarki z powrotem na serwer, udowadniając serwerowi, że strona wysyłająca żądanie jest zatwierdzona (wygenerowana przez, nawet) ten serwer.
Na moje pytanie, które dotyczy konkretnej metody transportu użytej dla tego tokenu CSRF w tej rundzie.
Wydaje się powszechne (np. W AngularJS , Django , Rails ) wysyłanie tokena CSRF z serwera do klienta jako pliku cookie (tj. W nagłówku Set-Cookie), a następnie JavaScript w kliencie zeskrobuje go z pliku cookie i dołącza jako osobny nagłówek XSRF-TOKEN, aby wysłać go z powrotem na serwer.
(Alternatywną metodą jest metoda zalecana np. Przez Express , gdzie token CSRF wygenerowany przez serwer jest zawarty w treści odpowiedzi poprzez rozwinięcie szablonu po stronie serwera, dołączony bezpośrednio do kodu / znaczników, które dostarczą go z powrotem do serwera, np. jako ukryte dane wejściowe. Ten przykład jest bardziej internetowym sposobem robienia rzeczy, ale uogólniałby się na klienta bardziej obciążonego JS).
Dlaczego tak często używa się Set-Cookie jako dalszego transportu tokena CSRF / dlaczego to dobry pomysł? Wyobrażam sobie, że autorzy wszystkich tych frameworków uważnie rozważali swoje opcje i nie zrozumieli tego źle. Ale na pierwszy rzut oka używanie plików cookie do obejścia tego, co jest zasadniczo ograniczeniem projektowym plików cookie, wydaje się głupie. W rzeczywistości, jeśli użyłeś plików cookie jako transportu w obie strony (Set-Cookie: nagłówek w dół dla serwera, aby poinformować przeglądarkę o tokenie CSRF, a Cookie: nagłówek w górę, aby przeglądarka zwróciła go na serwer), ponownie wprowadziłbyś lukę próbują to naprawić.
Zdaję sobie sprawę z tego, że powyższe ramy nie używają plików cookie przez całą podróż do tokena CSRF; wykorzystują Set-Cookie w dół, a następnie coś innego (np. nagłówek Token X-CSRF) w górę, a to eliminuje lukę. Ale nawet stosowanie Set-Cookie jako dalszego transportu jest potencjalnie mylące i niebezpieczne; przeglądarka będzie teraz dołączać token CSRF do każdego żądania, w tym autentyczne złośliwe żądania XSRF; co najwyżej sprawia, że żądanie jest większe, niż powinno być, a w najgorszym przypadku jakiś sensowny, ale źle wprowadzony fragment kodu serwera może faktycznie spróbować go użyć, co byłoby naprawdę złe. Ponadto, ponieważ faktycznym zamierzonym odbiorcą tokenu CSRF jest JavaScript po stronie klienta, oznacza to, że ten plik cookie nie może być chroniony tylko za pomocą protokołu HTTP.
Odpowiedzi:
Dobrym powodem, który poruszyłeś, jest to, że po otrzymaniu pliku cookie CSRF jest on następnie dostępny do użycia w całej aplikacji w skrypcie klienta do użycia zarówno w zwykłych formularzach, jak i AJAX POST. Będzie to miało sens w aplikacji obsługującej JavaScript, takiej jak ta używana przez AngularJS (użycie AngularJS nie wymaga, aby aplikacja była aplikacją jednostronicową, więc byłoby użyteczne tam, gdzie stan musi przepływać między różnymi żądaniami stron, gdzie wartość CSRF normalnie nie może pozostać w przeglądarce).
Rozważ następujące scenariusze i procesy w typowej aplikacji dla niektórych zalet i wad każdego opisanego podejścia. Są one oparte na sygnaturze tokenu synchronizatora .
Poproś o podejście do ciała
Zalety:
Niedogodności:
Niestandardowy nagłówek HTTP (pobieranie danych)
Zalety:
Niedogodności:
Niestandardowy nagłówek HTTP (upstream)
Zalety:
Niedogodności:
Niestandardowy nagłówek HTTP (upstream i downstream)
Zalety:
Niedogodności:
Zestaw ciasteczek
Zalety:
Niedogodności:
Dlatego podejście do plików cookie jest dość dynamiczne, oferując łatwy sposób na uzyskanie wartości pliku cookie (dowolnego żądania HTTP) i jego użycie (JS może automatycznie dodać wartość do dowolnego formularza i może być stosowany w żądaniach AJAX jako nagłówek lub jako wartość formularza). Po otrzymaniu tokenu CSRF dla sesji nie ma potrzeby jego ponownego generowania, ponieważ osoba atakująca wykorzystująca exploit CSRF nie ma metody odzyskania tego tokena. Jeśli złośliwy użytkownik spróbuje odczytać token CSRF użytkownika za pomocą dowolnej z powyższych metod, zapobiegną temu zasady dotyczące tego samego pochodzenia . Jeśli złośliwy użytkownik próbuje odzyskać stronę tokena CSRF po stronie serwera (np. Za pośrednictwem
curl
), to token nie zostanie powiązany z tym samym kontem użytkownika, ponieważ w żądaniu brak będzie pliku cookie sesji uwierzytelnienia ofiary (byłby to atakujący - dlatego nie będzie powiązany ze stroną serwera z sesją ofiary).Oprócz wzorca tokena synchronizującego istnieje również plik cookie podwójnego przesyłaniaMetoda zapobiegania CSRF, która oczywiście wykorzystuje pliki cookie do przechowywania pewnego rodzaju tokenu CSRF. Jest to łatwiejsze do wdrożenia, ponieważ nie wymaga żadnego stanu po stronie serwera dla tokena CSRF. Token CSRF może w rzeczywistości być standardowym plikiem cookie uwierzytelniania podczas korzystania z tej metody, a ta wartość jest przesyłana za pośrednictwem plików cookie jak zwykle wraz z żądaniem, ale wartość jest również powtarzana w ukrytym polu lub nagłówku, którego atakujący nie może replikować jako przede wszystkim nie mogą odczytać wartości. Zaleca się jednak wybranie innego pliku cookie, innego niż plik cookie służący do uwierzytelnienia, aby można było zabezpieczyć plik cookie służący do uwierzytelniania, oznaczając go jako HttpOnly. Jest to kolejny częsty powód, dla którego warto zapobiegać CSRF przy użyciu metody opartej na plikach cookie.
źródło
Użycie pliku cookie w celu dostarczenia tokena CSRF do klienta nie pozwala na udany atak, ponieważ osoba atakująca nie może odczytać wartości pliku cookie, a zatem nie może umieścić go tam, gdzie wymaga tego weryfikacja CSRF po stronie serwera.
Osoba atakująca będzie mogła wywołać żądanie do serwera, używając zarówno pliku cookie tokenu uwierzytelniania, jak i pliku cookie CSRF w nagłówkach żądania. Ale serwer nie szuka tokena CSRF jako pliku cookie w nagłówkach żądania, szuka w ładunku żądania. I nawet jeśli atakujący wie, gdzie umieścić token CSRF w ładunku, musiałby odczytać jego wartość, aby go tam umieścić. Ale zasady dotyczące różnych źródeł w przeglądarce uniemożliwiają odczytanie wartości plików cookie z docelowej witryny.
Ta sama logika nie dotyczy pliku cookie tokenu uwierzytelniania, ponieważ serwer oczekuje go w nagłówkach żądania, a atakujący nie musi robić nic specjalnego, aby go tam umieścić.
źródło
src='bank.com/transfer?to=hacker&amount=1000
którą poprosi przeglądarka, wraz z powiązanymi plikami cookie dla tej witryny (bank.com
)?Moje najlepsze przypuszczenie, co do odpowiedzi: Rozważ te 3 opcje, w jaki sposób pobrać token CSRF z serwera do przeglądarki.
Wydaje mi się, że pierwszy, „ciało żądania” (chociaż zademonstrowany w tutorialu Express, do którego włączyłem pytanie ), nie jest tak przenośny w wielu różnych sytuacjach; nie każdy generuje każdą odpowiedź HTTP dynamicznie; gdzie w końcu musisz wstawić token do generowanej odpowiedzi, może się znacznie różnić (w postaci ukrytej danych wejściowych; fragmentu kodu JS lub zmiennej dostępnej za pomocą innego kodu JS; może nawet w adresie URL, choć wydaje się to ogólnie złe miejsce umieścić tokeny CSRF). Tak więc, choć wykonalne z pewnymi dostosowaniami, # 1 jest trudnym miejscem do przyjęcia uniwersalnego podejścia.
Drugi, niestandardowy nagłówek, jest atrakcyjny, ale w rzeczywistości nie działa, ponieważ chociaż JS może pobrać nagłówki dla XHR, które wywołał, nie może pobrać nagłówków dla strony, z której został załadowany .
To pozostawia trzeci, plik cookie przenoszony przez nagłówek Set-Cookie, jako podejście, które jest łatwe w użyciu we wszystkich sytuacjach (każdy serwer będzie mógł ustawić nagłówki plików cookie na żądanie i nie ma znaczenia, jakiego rodzaju dane znajdują się w treści żądania). Mimo swoich wad był to najłatwiejszy sposób na szerokie wdrożenie ram.
źródło
Poza sesyjnym plikiem cookie (który jest rodzajem standardu), nie chcę używać dodatkowych plików cookie.
Znalazłem rozwiązanie, które działa dla mnie przy tworzeniu aplikacji jednostronicowej (SPA) z wieloma żądaniami AJAX. Uwaga: używam JQuery po stronie serwera i JQuery po stronie klienta, ale nie ma magicznych rzeczy, więc myślę, że tę zasadę można wdrożyć we wszystkich popularnych językach programowania.
Moje rozwiązanie bez dodatkowych plików cookie jest proste:
Strona klienta
Przechowuj token CSRF, który jest zwracany przez serwer po udanym logowaniu w zmiennej globalnej (jeśli chcesz użyć magazynu internetowego zamiast globalnego, to w porządku). Poinstruuj JQuery, aby w każdym wywołaniu AJAX podawał nagłówek X-CSRF-TOKEN.
Główna strona „indeksu” zawiera ten fragment kodu JavaScript:
Po stronie serwera
Przy kolejnym logowaniu utwórz losowy (i wystarczająco długi) token CSRF, zapisz go w sesji po stronie serwera i zwróć klientowi. Filtruj określone (wrażliwe) przychodzące żądania, porównując wartość nagłówka X-CSRF-TOKEN z wartością zapisaną w sesji: powinny się zgadzać.
Wrażliwe wywołania AJAX (dane formularza POST i GET JSON-data) oraz przechwytywanie ich przez filtr po stronie serwera znajdują się w ścieżce / dataservice / *. Żądania logowania nie mogą trafić w filtr, więc są na innej ścieżce. Żądania dotyczące HTML, CSS, JS i zasobów graficznych również nie znajdują się na ścieżce / dataservice / *, dlatego nie są filtrowane. Nie zawierają one żadnych tajemnic i nie mogą wyrządzić krzywdy, więc jest w porządku.
źródło