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:
- Akcja warta przejęcia – zmiana e-maila, hasła, transfer środków, zmiana uprawnień.
- Uwierzytelnianie oparte wyłącznie o ciasteczka – sesja jest identyfikowana przez cookie dołączane automatycznie.
- Przewidywalne parametry żądania – atakujący zna lub odgaduje strukturę żądania.
- 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">
</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
- Przechwyć podatne żądanie w Burp Proxy.
- Kliknij prawym →
Engagement tools→Generate CSRF PoC. - Burp wygeneruje gotowy formularz HTML do testu.
- Zapisz jako
.htmli 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/jsonwymusza preflight CORS. Test: czy serwer akceptujetext/plainlubapplication/x-www-form-urlencodedz 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 — sprawdzajOrigin/Content-Typealbo wymagaj nagłówka spoza listy CORS-safelisted. Test wprost z wymagania: na każdy endpoint zmieniający stan wyślij ciało JSON zContent-Type: text/plainbez 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)!