Przejdź do głównej zawartości

Cross-Site Request Forgery (CSRF)

CSRF (Cross-Site Request Forgery) to atak, w którym napastnik zmusza zalogowanego użytkownika do wykonania niezamierzonej akcji w aplikacji, której ten użytkownik ufa. Aplikacja wykonuje żądanie, bo przeglądarka automatycznie dołącza ciasteczka sesyjne — nawet jeśli żądanie pochodzi z obcej domeny.


Jak działa CSRF?​

Warunki konieczne, by atak był możliwy:

  1. Akcja warta przejęcia – zmiana e-maila, hasła, transfer środków, zmiana uprawnień.
  2. Uwierzytelnianie oparte wyłącznie o ciasteczka – sesja jest identyfikowana przez cookie dołączane automatycznie.
  3. Przewidywalne parametry żądania – atakujący zna lub odgaduje strukturę żądania.
  4. Brak nieprzewidywalnego tokenu – żądanie nie wymaga wartości, której atakujący nie może poznać (anty-CSRF token).

Przykładowe podatne żądanie zmiany e-maila:

POST /account/email HTTP/1.1
Host: example.com
Cookie: session=eyJhbGc...
Content-Type: application/x-www-form-urlencoded

Jeśli to wszystko, czego wymaga serwer — żądanie da się sfałszować z dowolnej strony.


Eksploatacja CSRF​

1️⃣ CSRF przez formularz HTML (POST)​

Atakujący umieszcza na swojej stronie ukryty formularz, który wysyła się automatycznie:

<html>
<body onload="document.forms[0].submit()">
<form action="https://example.com/account/email" method="POST">
<input type="hidden" name="email" value="[email protected]">
</form>
</body>
</html>

Gdy zalogowana ofiara odwiedzi tę stronę, jej e-mail konta zostanie podmieniony.

2️⃣ CSRF przez żądanie GET​

Jeśli akcja zmieniająca stan jest dostępna przez GET (zły wzorzec) — wystarczy znacznik obrazka:

<img src="https://example.com/account/delete?confirm=true">

3️⃣ Generowanie PoC w Burp Suite​

  1. Przechwyć podatne żądanie w Burp Proxy.
  2. Kliknij prawym → Engagement tools → Generate CSRF PoC.
  3. Burp wygeneruje gotowy formularz HTML do testu.
  4. Zapisz jako .html i otwórz w sesji zalogowanej ofiary.

Obejście zabezpieczeń CSRF​

1️⃣ Token przesyłany, ale nieweryfikowany​

Niektóre aplikacje generują token, ale go nie sprawdzają. Test: usuń parametr tokenu z żądania — jeśli akcja się powiedzie, ochrona jest pozorna.

2️⃣ Token weryfikowany tylko, gdy obecny​

Jeśli usunięcie całego parametru tokenu omija walidację (a tylko zła wartość ją uruchamia) — atak jest możliwy bez znajomości tokenu.

3️⃣ Token powiązany z pulą, nie z użytkownikiem​

Czasem token jest poprawny dla dowolnego konta. Atakujący pobiera własny token i wkleja go w żądaniu ofiary.

4️⃣ Token w ciasteczku zamiast w stanie serwera (Double-Submit bypass)​

Jeśli token jest porównywany między ciasteczkiem a parametrem, a atakujący potrafi ustawić ciasteczko (np. przez subdomenę lub podatność na cookie injection) — może dopasować obie wartości.

5️⃣ Obejście walidacji nagłówka Referer​

Gdy ochrona opiera się o Referer:

<meta name="referrer" content="no-referrer">

Usunięcie nagłówka Referer może obejść walidację, jeśli serwer akceptuje żądania bez Referera.


CSRF a SameSite i CORS​

  • SameSite=Lax (domyślne w nowoczesnych przeglądarkach) blokuje wysyłanie ciasteczek przy cross-site POST, ale nie przy nawigacji GET top-level — dlatego akcje zmieniające stan przez GET nadal bywają podatne.
  • SameSite=None (wymagane dla flow cross-site) przywraca pełną podatność, jeśli brak tokenu.
  • CSRF na endpointach JSON bywa trudniejszy: Content-Type: application/json wymusza preflight CORS. Test: czy serwer akceptuje text/plain lub application/x-www-form-urlencoded z payloadem JSON-podobnym.
<form action="https://example.com/api/transfer" method="POST" enctype="text/plain">
<input name='{"amount":10000,"to":"evil","ignore":"' value='"}'>
</form>

🧭 Zasada: obrona oparta na preflighcie jest niejawna i pęka po cichu. Ochrona API JSON przez wymuszony preflight nie jest nigdzie napisana — wynika z tego, jakich żądań serwer nie przyjmuje. Dlatego psuje ją zmiana, która wygląda na ułatwienie: parser akceptujący też text/plain, endpoint, który od teraz przyjmuje zwykły formularz (simple request nie wyzwala preflightu), albo akcja przeniesiona na GET. ASVS 5.0 stawia to jako osobny warunek (3.5.2, L1): jeśli polegasz na preflighcie, musi być niemożliwe wywołanie funkcji żądaniem, które preflightu nie wyzwala — sprawdzaj Origin/Content-Type albo wymagaj nagłówka spoza listy CORS-safelisted. Test wprost z wymagania: na każdy endpoint zmieniający stan wyślij ciało JSON z Content-Type: text/plain bez niestandardowych nagłówków — oczekiwany wynik to odrzucenie (np. 415), a nie wykonanie. Żadna konfiguracja CORS tego nie pokaże. — OWASP ASVS 5.0, s. 35–36 (3.5.1–3.5.3)


Jak zabezpieczyć aplikację przed CSRF?​

✅ Stosuj anty-CSRF tokeny (synchronizer token pattern) – unikalne per sesja/żądanie i weryfikowane po stronie serwera. ✅ Ustaw SameSite=Lax lub Strict dla ciasteczek sesyjnych. ✅ Nie zmieniaj stanu przez żądania GET. ✅ Wymagaj ponownego uwierzytelnienia dla operacji krytycznych (zmiana hasła, e-maila, płatności). ✅ Weryfikuj nagłówki Origin/Referer jako warstwę dodatkową, nie jedyną.


CSRF wykorzystuje zaufanie aplikacji do przeglądarki użytkownika. Kolejnym krokiem będzie analiza podatności XML External Entity (XXE)!