Piszę aplikację (Django, tak się zdarza) i chcę po prostu wiedzieć, czym tak naprawdę jest „token CSRF” i jak chroni dane. Czy dane pocztowe nie są bezpieczne, jeśli nie korzystasz z tokenów CSRF?
Piszę aplikację (Django, tak się zdarza) i chcę po prostu wiedzieć, czym tak naprawdę jest „token CSRF” i jak chroni dane. Czy dane pocztowe nie są bezpieczne, jeśli nie korzystasz z tokenów CSRF?
Odpowiedzi:
www.mybank.com
mybank.com
spowoduje przesłanie formularza (koncepcyjnie) http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>
. (Twój numer konta nie jest potrzebny, ponieważ wynika z twojego loginu.)www.cute-cat-pictures.org
, nie wiedząc, że jest to złośliwa strona.mybank.com
(wymaga odrobiny szczęścia!), Może dołączyć na swojej stronie żądanie takie jak http://www.mybank.com/transfer?to=123456;amount=10000
(gdzie 123456
jest numer ich konta na Kajmanach i 10000
jest to kwota, którą wcześniej myślałeś, że jesteś zadowolony z ją posiadasz).www.cute-cat-pictures.org
stronę, więc Twoja przeglądarka uczyni ten wniosek.www.mybank.com
plikiem cookie i będzie wyglądać całkowicie poprawnie. Tam idą twoje pieniądze!To świat bez tokenów CSRF .
Teraz lepszy z tokenami CSRF :
http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971
.mybank.com
pojawi się na własnej stronie internetowej, gdy Ci ją poda. To jest inna za każdym razem służą dowolną stronę nikomu.www.mybank.com
.Wynik: zachowujesz swoje 10000
jednostki pieniężne. Proponuję przekazać trochę tego na Wikipedię.
(Twój przebieg może się różnić.)
EDYTUJ z komentarza, który warto przeczytać:
Warto zauważyć, że skrypt z www.cute-cat-pictures.org
reguły nie ma dostępu do tokena anty-CSRF z www.mybank.com
powodu kontroli dostępu HTTP. Ta notatka jest ważna dla niektórych osób, które nierozsądnie wysyłają nagłówek Access-Control-Allow-Origin: *
dla każdej odpowiedzi strony internetowej, nie wiedząc, do czego to służy, tylko dlatego, że nie mogą używać interfejsu API z innej witryny.
www.cute-cat-pictures.org
reguły nie ma dostępu do tokena anty-CSRF z www.mybank.com
powodu kontroli dostępu HTTP. Ta notatka jest ważna dla niektórych osób, które nierozsądnie wysyłają nagłówek Access-Control-Allow-Origin: *
dla każdej odpowiedzi strony internetowej, nie wiedząc, do czego to służy, tylko dlatego, że nie mogą używać interfejsu API z innej witryny.
Tak, dane wpisu są bezpieczne. Ale pochodzenie tych danych nie jest. W ten sposób ktoś może nakłonić użytkownika JS do zalogowania się na Twojej stronie podczas przeglądania strony atakującego.
Aby temu zapobiec, django wyśle losowy klucz zarówno w pliku cookie, jak i danych formularza. Następnie, gdy użytkownicy POST, sprawdzą, czy dwa klucze są identyczne. W przypadku oszukania użytkownika witryna innej firmy nie może uzyskać plików cookie witryny, co powoduje błąd uwierzytelnienia.
Witryna generuje unikalny token podczas tworzenia strony formularza. Ten token jest wymagany do wysyłania / pobierania danych z powrotem na serwer.
Ponieważ token jest generowany przez twoją witrynę i dostarczany tylko wtedy, gdy strona z formularzem jest generowana, niektóre inne witryny nie mogą naśladować twoich formularzy - nie będą miały tokenów i dlatego nie będą mogły publikować na twojej stronie.
Blog Cloud Under ma dobre objaśnienie tokenów CSRF.
Wyobraź sobie, że masz witrynę internetową jak uproszczony Twitter, hostowaną na a.com. Zalogowani użytkownicy mogą wprowadzić tekst (tweet) do formularza, który jest wysyłany na serwer jako żądanie POST i publikowany po naciśnięciu przycisku przesyłania. Na serwerze użytkownik jest identyfikowany przez plik cookie zawierający jego unikalny identyfikator sesji, dzięki czemu Twój serwer wie, kto opublikował tweeta.
Formularz może być tak prosty:
<form action="http://a.com/tweet" method="POST"> <input type="text" name="tweet"> <input type="submit"> </form>
Teraz wyobraź sobie, że zły facet kopiuje i wkleja ten formularz do swojej złośliwej strony, powiedzmy b.com. Formularz nadal działałby. Tak długo, jak użytkownik jest zalogowany na Twoim Twitterze (tj. Ma prawidłowy plik cookie sesji dla a.com), żądanie POST będzie wysyłane
http://a.com/tweet
i przetwarzane jak zwykle, gdy użytkownik kliknie przycisk przesyłania.Jak dotąd nie jest to duży problem, o ile użytkownik zostanie poinformowany o tym, co dokładnie robi formularz, ale co, jeśli nasz zły facet poprawi formularz w ten sposób:
<form action="https://example.com/tweet" method="POST"> <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad"> <input type="submit" value="Click to win!"> </form>
Teraz, jeśli jeden z Twoich użytkowników znajdzie się na stronie złego faceta i kliknie „Kliknij, aby wygrać!” przycisk, formularz jest przesyłany do Twojej witryny, użytkownik jest poprawnie identyfikowany przez identyfikator sesji w pliku cookie, a ukryty Tweet zostaje opublikowany.
Gdyby nasz zły facet był jeszcze gorszy, zmusiłby niewinnego użytkownika do przesłania tego formularza, gdy tylko otworzą swoją stronę internetową za pomocą JavaScript, być może nawet całkowicie ukrytego w niewidzialnym iframe. Zasadniczo jest to fałszowanie żądań w różnych witrynach.
Formularz można łatwo przesłać z dowolnego miejsca na cały. Zasadniczo jest to wspólna funkcja, ale istnieje wiele innych przypadków, w których ważne jest, aby zezwolić na przesyłanie formularza tylko z domeny, do której należy.
Gorzej, jeśli twoja aplikacja internetowa nie rozróżnia żądań POST i GET (np. W PHP za pomocą $ _REQUEST zamiast $ _POST). Nie rób tego! Żądania zmiany danych mogą być przesyłane tak łatwo, jak
<img src="http://a.com/tweet?tweet=This+is+really+bad">
osadzone w złośliwej witrynie lub nawet w wiadomości e-mail.Jak mogę się upewnić, że formularz można przesłać tylko z mojej strony internetowej? W tym miejscu pojawia się token CSRF. Token CSRF to losowy, trudny do odgadnięcia ciąg. Na stronie z formularzem, który chcesz chronić, serwer wygeneruje losowy ciąg, token CSRF, doda go do formularza jako ukrytego pola, a także zapamięta w jakiś sposób, przechowując go w sesji lub ustawiając plik cookie zawierający wartość. Teraz formularz będzie wyglądał następująco:
<form action="https://example.com/tweet" method="POST"> <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn"> <input type="text" name="tweet"> <input type="submit"> </form>
Gdy użytkownik prześle formularz, serwer musi po prostu porównać wartość wysłanego pola csrf-token (nazwa nie ma znaczenia) z tokenem CSRF zapamiętanym przez serwer. Jeśli oba ciągi są równe, serwer może kontynuować przetwarzanie formularza. W przeciwnym razie serwer powinien natychmiast przerwać przetwarzanie formularza i odpowiedzieć błędem.
Dlaczego to działa? Istnieje kilka powodów, dla których zły facet z powyższego przykładu nie może uzyskać tokenu CSRF:
Kopiowanie statycznego kodu źródłowego z naszej strony na inną stronę byłoby bezużyteczne, ponieważ wartość ukrytego pola zmienia się u każdego użytkownika. Bez strony internetowej złego faceta, która zna token CSRF bieżącego użytkownika, Twój serwer zawsze odrzuca żądanie POST.
Ponieważ złośliwa strona złego faceta jest ładowana przez przeglądarkę użytkownika z innej domeny (b.com zamiast a.com), złoczyńca nie ma szans na kodowanie JavaScript, który ładuje treść, a zatem bieżący token CSRF naszego użytkownika z Twoja strona internetowa. Wynika to z faktu, że przeglądarki internetowe domyślnie nie obsługują żądań AJAX między domenami.
Zły facet również nie może uzyskać dostępu do pliku cookie ustawionego przez serwer, ponieważ domeny się nie zgadzają.
Kiedy powinienem zabezpieczyć się przed fałszowaniem żądań w różnych witrynach? Jeśli możesz upewnić się, że nie pomieszasz metod GET, POST i innych metod żądania opisanych powyżej, dobrym początkiem byłoby domyślnie zabezpieczenie wszystkich żądań POST.
Nie musisz chronić żądań PUT i DELETE, ponieważ jak wyjaśniono powyżej, standardowy formularz HTML nie może zostać przesłany przez przeglądarkę przy użyciu tych metod.
Z drugiej strony JavaScript może faktycznie wysyłać inne typy żądań, np. Używając funkcji $ .ajax () jQuery, ale pamiętaj, że aby żądania AJAX działały, domeny muszą się zgadzać (o ile nie skonfigurujesz inaczej serwera WWW) .
Oznacza to, że często nie musisz nawet dodawać tokena CSRF do żądań AJAX, nawet jeśli są to żądania POST, ale musisz upewnić się, że pomijasz sprawdzanie CSRF w swojej aplikacji internetowej, jeśli żądanie POST jest w rzeczywistości Żądanie AJAX. Możesz to zrobić, szukając obecności nagłówka takiego jak X-Requested-With, który zwykle zawiera żądania AJAX. Możesz także ustawić inny niestandardowy nagłówek i sprawdzić jego obecność po stronie serwera. Jest to bezpieczne, ponieważ przeglądarka nie dodawała niestandardowych nagłówków do zwykłego przesyłania formularza HTML (patrz wyżej), więc Pan Bad Guy nie ma szans na symulację tego zachowania za pomocą formularza.
Jeśli masz wątpliwości co do żądań AJAX, ponieważ z jakiegoś powodu nie możesz sprawdzić nagłówka takiego jak X-Requested-With, po prostu przekaż wygenerowany token CSRF do JavaScript i dodaj token do żądania AJAX. Można to zrobić na kilka sposobów; albo dodaj go do ładunku, jak zwykły formularz HTML, lub dodaj niestandardowy nagłówek do żądania AJAX. Tak długo, jak twój serwer wie, gdzie go szukać w przychodzącym żądaniu i jest w stanie porównać go z oryginalną wartością, którą pamięta z sesji lub pliku cookie, jesteś sortowany.
Podstawą tego wszystkiego jest upewnienie się, że żądania pochodzą od rzeczywistych użytkowników witryny. Token csrf jest generowany dla formularzy i musi być powiązany z sesjami użytkownika. Służy do wysyłania żądań do serwera, na którym token je weryfikuje. Jest to jeden ze sposobów ochrony przed csrf, innym sposobem byłoby sprawdzenie nagłówka strony odsyłającej.