PHPCenter - Twoje Centrum Informacji - PHP, Szkolenia, Biblioteki, Licencje i nie tylko...
Twoje Centrum Informacji
PHP, Szkolenia i nie tylko...

Token CSRF – Zabezpieczanie aplikacji przed niekontrolowanym wykonaniem operacji

Gdy jesteś zalogowany do Facebooka, Twittera czy Allegro, masz możliwość zamawiania produktów, komentowania czy wstawiania postów. Wszystkie te akcje są możliwe dzięki zalogowaniu się do danego portalu. Dopóki się nie wylogujesz, te operacje możesz wykonywać nawet wtedy, gdy zamkniesz przeglądarkę i otworzysz ją jutro. Nam – użytkownikom – daje to wielką swobodę i szybkość, jednak przysparza wiele problemów developerom.

Wielcy gracze na rynku, o których wspomniałem wyżej, posiadają różne sposoby zabezpieczania formularzy do komentowania, czy zakupów. Ale jest wiele stron, które takiego zabezpieczenia nie posiadają. Strony takie są podatne na różne ataki, a jednym z tych ataków jest jest CSRF (Cross-site request forgery).

Podatność ta umożliwia wykonanie określonej, newralgicznej akcji na stronie, bez dostępu fizycznego do Twojego konta. Wystarczy, że będziesz
zalogowany na stronie (Facebook, Poczta, Allegro), a atakujący podeśle Ci odpowiednio spreparowany link, w który klikniesz.

W artykule tym dowiesz się jak zabezpieczyć swoją aplikację przed tego typu atakiem. Przedstawię również dodatkową metodę zabezpieczania takich operacji. Obydwie metody powinny iść w parze.

Przykład ataku z użyciem podatności CSRF

Jesteś zalogowany do swojego bloga, w którym posiadasz artykuły. Każdy z artykułów możesz usunąć, poprzez kliknięcie przycisku z następującym linkiem:

http://mojastrona.pl/admin/article/remove/1234

Nawet jeśli ktokolwiek wyśle Ci taki link, zapewne nie wejdziesz na niego. Na pierwszy rzut oka widać co ten link robi. Jest jednak inne wyjście, które umożliwi wykonanie tego linku:

<img src="http://mojastrona.pl/admin/article/remove/1234" />

Można więc umieścić ten link w obrazku, a następnie wysłać taki obrazek w treści maila. Gdy tylko otworzysz tą wiadomość, przeglądarka automatycznie będzie chciała go pobrać. Jednak zamiast linku do obrazka widnieje w nim link do usuwania artykułu. Próba pobrania obrazka przez przeglądarkę spowoduje odwołanie się do tej podstrony i w efekcie usunięcie artykułu.

Tak, wiem, większość skrzynek pocztowych blokuje pobieranie obrazków przy wyświetlaniu wiadomości. Masz rację. A co jeśli ktoś zamieści taki obrazek na stronie internetowej, na którą wejdziesz? Tutaj już nie ma żadnego zabezpieczenia – przeglądarka wykona żądanie.

Jednym z lepszych rozwiązań tego problemu jest Token CSRF.

Czym jest token?

Token to pewien losowy ciąg znaków, wygenerowany z użyciem konkretnego algorytmu hashującego (MD5 – unikaj jak ognia!, SHA-256). Taki token z powinien być jednorazowy. Oznacza to, że gdy już raz go użyjesz, nie powinieneś na nim więcej polegać. W rzeczywistym przykładzie, powinieneś usunąć dany token z listy dostępnych od razu, gdy w danym żądaniu zostanie on wysłany. A jeśli potrzebny jest on ponownie – powinieneś wygenerować nowy w jego miejsce.

Jak użyć tokenów by zabezpieczyć stronę?

Wygenerowane tokeny CSRF przechowuje się w większości przypadków w sesji. Zaletą tego jest szybkość dostępu do tokenów, oraz brak potrzeby ustalania czasu życia tokenów – koniec sesji oznacza usunięcie wszystkich tokenów dla danego użytkownika. Dany token jest wygenerowany tylko i wyłącznie dla jednego zalogowanego użytkownika. Nie może zajść sytuacja, gdy jeden token będzie użyty dla kilku użytkowników.

Najprostszym sposobem jest umieszczenie tokenu w adresie URL:

http://mojastrona.pl/admin/article/remove/1234?csrf=ytf67btrf4btRDb6rdbYR

W akcji kontrolera powinieneś sprawdzić natomiast, czy token z adresu URL znajduje się na liście wygenerowanych do tej pory tokenów. Jeśli tak – można usunąć artykuł. I nie zapomnij usunąć tokenu z listy (z sesji)!.

A co z tym dodatkowym zabezpieczeniem?

Dodatkowo można zamienić metodę żądania z GET na POST i użyć prostego formularza, zamiast linku:

<form action="http://mojastrona.pl/admin/article/remove/1234" method="post">
    <input type="hidden" name="csrf-token" value="ytf67btrf4btRDb6rdbYR" />
    <button type="submit">Usuń artykuł</button>
</form>

Zalecam zamienić wszystkie akcje, które wykonują operacje w bazie danych, na obsługę metodą POST. Utrudnia to wykonanie ataku. W wielu przypadkach będzie to wymagało więcej pracy, jednak zwróci się to w kwestii bezpieczeństwa aplikacji. Nawet jeśli zapomnisz użyć tokenu CSRF, to aplikacja będzie wymagała metody POST by wykonać akcję, a tą jest trudno wykonać bez użycia JavaScriptu.

Porada

Gdy używasz systemu szablonów, możesz stworzyć funkcję/makro, które będzie automatycznie generowało formularz, a Ty prześlesz tylko adres URL na który ma zostać wysłany formularz.

Przykład

Informacja

Poniższe przykłady używają pseudokodu i mogą nie działać bezpośrednio po skopiowaniu, jest to podglądowy kod do zobrazowania zasady działania.

Przykład kodu do generowania unikalnych tokenów:

function generateToken()
{
   return bin2hex(random_bytes(64));
}

Zapisujemy tak wygenerowany token do sesji:

$token = generateToken();
$session->append('csrf_tokens', $token);

Wyświetlamy token w formularzu:

<form action="" method="post">
    <input type="hidden" name="__csrf_token" value="<?= $token ?>" />
</form>

Ostatnim krokiem, po wysłaniu takiego formularza jest sprawdzenie czy
token z formularza istnieje w sesji:

$token  = $request->get('__csrf_token');
$tokens = $session->getAll('csrf_tokens');

// Tokenu nie ma na liście, robimy przekierowanie
// na stronę z błędem lub wykonujemy inną operację
if(in_array($tokens, $token) === false)
    return $this->redirect(/*...*/);

// Token istnieje, więc go usuwamy z listy i wykonujemy aplikację dalej
$session->removeValue('csrf_tokens', $token);

A czy Ty używasz tokenów CSRF? A może masz inny sposób na zabezpieczenie aplikacji przez atakiem CSRF? Podziel się tym z nami.

2272cookie-checkToken CSRF – Zabezpieczanie aplikacji przed niekontrolowanym wykonaniem operacji
A co tam, udostępnij:
avatar
  Subscribe  
Powiadom o
Podoba Ci się to co czytasz, chcesz więcej treści od phpcenter.pl?
×
Wyszukaj