Aby chronić się przed CSRF, należy umieścić numer w ukrytym polu w formularzu oraz w pliku cookie lub w zmiennej sesji. Ale co, jeśli użytkownik otworzy kilka stron w różnych zakładkach? W takim przypadku każda karta miałaby postać z niepowtarzalnym nonce, ale w zmiennej sesji lub pliku cookie byłby tylko jeden element jednorazowy. Lub, jeśli spróbujesz zapisać wszystkie noncesy w zmiennej cookie/sesja, jak zidentyfikować, który z nich należy do której formy?Ochrona CSRF poprzez przechowywanie nonce w zmiennej Sesji i formie
Odpowiedz
Możesz przechowywać ten sam brak w każdym z formularzy. Najprostszym sposobem jest powiązanie numeru do identyfikatora sesji, aby te formularze działały tylko w tej sesji.
Będziesz chciał utrudnić atakującym identyfikatory sesji i stworzyć własne dane. Jednym ze sposobów na to jest użycie HMAC-SHA256 (lub podobnego) do zaszyfrowania identyfikatora sesji za pomocą klucza, którego nie ujawniasz publicznie.
(Oczywiście, jeśli osoba atakująca może uzyskać rzeczywisty identyfikator sesji, może ona już przechwytywać sesję, więc nie o to mi chodzi, ale raczej zdolność atakującego do stworzenia skryptu (który działa na komputer ofiary), które mogą w jakiś sposób pobrać identyfikator sesji i użyć jej do dynamicznego generowania adresów URL z nonce wstępnie wypełnione)
ETA. Czy powyższe podejście jest w stanie sama zależy od tego jak długo można się spodziewać Twoje typowe sesje do końca. Jeśli użytkownicy zwykle korzystają z długotrwałych sesji obejmujących więcej niż kilka godzin, musisz użyć czegoś bardziej wyrafinowanego.
Jedno podejście do tworzenia nowego nonce dla każdej postaci, która zawiera znacznik czasu, jak również hash(timestamp . sessionid)
(gdzie hash
jest kilka wariantów HMAC jak opisano powyżej, w celu zapobiegania fałszowaniu i .
jest łańcuch konkatenacji). Następnie zweryfikować nonce przez:
- sprawdzenie znacznika czasu, aby upewnić się, że nonce jest wystarczająco świeże (to jest do swojej polityki, ale kilka godzin jest typowy)
- wtedy, obliczanie wartości mieszania w oparciu o sygnatury czasowej i identyfikatora sesji oraz porównania w stosunku do wartości jednorazowej, aby sprawdzić, czy numer jednorazowy jest autentyczny:
Jeśli kontrola numeru nie powiedzie się, konieczne będzie wyświetlenie nowego formularza wypełnionego wcześniej przez użytkownika (aby jeśli zajęliby cały dzień, aby napisać swoje stanowisko, nie stracą całej swojej ciężkiej pracy), a także świeżego pobytu. Następnie użytkownik może ponownie przesłać ponownie pomyślnie.
Niektóre osoby generują token dla każdej formy, co jest bardzo bezpiecznym podejściem. Może to jednak spowodować uszkodzenie aplikacji i wkurzenie użytkowników. Aby zapobiec wszelkiemu XSRF przeciwko twojej witrynie, potrzebujesz tylko unikalnej 1 zmiennej tokena na sesję, a wtedy atakujący nie będzie w stanie sfałszować żadnych żądań, dopóki nie znajdzie tego 1 tokena. Drobny problem z tym podejściem polega na tym, że atakujący może brutalnie wymusić ten token, dopóki ofiara odwiedza witrynę, którą kontroluje osoba atakująca. JEDNAKŻE, jeśli token jest dość duży, jak 32 bajty, to potrzeba wiele lat, aby zmusić brute force, a sesja http powinna wygasnąć na długo przedtem.
Czy atakujący nie może poprosić o formularz, aby uzyskać ważny token? Wydaje się całkiem proste. –
@Chris Moschini nie działa w ten sposób xsrf. Jeździsz na czyjejś sesji, nie swojej, to po prostu nie ma sensu. – rook
Dzięki. A co, gdy serwer znajduje się za odwrotnym proxy i sesja HTTP jest odnawiana dla każdego żądania? –
Dawno temu ten post został napisany. Wdrożyłem bloker csrf, który jestem prawie pewien, chroni również. Działa z wieloma otwartymi oknami, ale wciąż oceniam rodzaj oferowanej ochrony. Używa podejścia DB, tj. Przechowywania zamiast sesji do tabeli. UWAGA: Używam MD5 w tym przypadku jako łatwy anty-sqli mechanizmu
pseudokod:
POSTAĆ:
token = randomstring #to be used in form hidden input
db->insert into csrf (token, user_id) values (md5(token),md5(cookie(user_id))
- token jest następnie przechowywane w db aż to dostępne z skrypt akcji, poniżej:
aCTION sCRIPT:
if md5(post(token)) belongs to md5(cookie(user_id))
#discard the token
db -> delete from csrf where token=md5(post(token)) and user_id=md5(cookie(user_id))
do the rest of the stuff
Dodanie identyfikatora użytkownika do rekordu nie zwiększa bezpieczeństwa, ale pozwala na usunięcie nieużywanych tokenów użytkownika z bazy danych po rozłączeniu. –
To, co opisujesz, nie jest już jednorazowe (nonce = numer użyty raz), to tylko identyfikator sesji. Cały punkt jednorazowy jest taki, że jest ważny tylko w przypadku pojedynczego przesłania formularza, dlatego zapewnia większe bezpieczeństwo przed przejęciem niż tylko identyfikator sesji, ale kosztem braku możliwości posiadania wielu kart działających równolegle na stronie.
Narkotyki są przesadne dla wielu celów. Jeśli ich używasz, powinieneś tylko ustawiać i wymagać od nich formularzy, które wprowadzają krytyczne zmiany w systemie, i edukować użytkowników, że nie mogą oczekiwać użycia więcej niż jednego takiego formularza równolegle. Strony, które nie ustawiają jednorazowości, powinny zadbać o to, aby nie usuwać z sesji żadnych wcześniej zapisanych zdarzeń, aby użytkownicy mogli nadal korzystać z nieobciążonych stron równolegle z niewymienionymi formularzami.
Więc nie generowałeś nowego numeru za każdym razem? Wartość jednorazowa byłaby taka sama podczas całej sesji i dla kilku zgłoszeń. – Marius
@Marius: Zaktualizuję moją odpowiedź, aby odpowiedzieć na Twój komentarz. :-) –
-1 Żaden atakujący NIE ma identyfikatora sesji, przeglądarka to robi. To NIE jest zadanie dla HMAC. – rook