CSRF Napadi — Cross-Site Request Forgery
Objavljeno: 8. april 2026. · Vreme citanja: 12 min
Sadrzaj
1. Sta je CSRF?
CSRF (Cross-Site Request Forgery), poznat i kao "session riding" ili "one-click attack", je vrsta napada na web aplikacije gde napadac navodi korisnikov browser da izvrsi nezeljenu akciju na sajtu na kome je korisnik trenutno autentifikovan.
Kljucna stvar kod CSRF-a je da napadac ne mora da zna korisnikovu lozinku. Browser automatski salje kolacice (cookies) sa svakim zahtevom ka domenu, pa ako je korisnik ulogovan na bankovni sajt i poseti malicioznu stranicu, ta stranica moze poslati zahtev ka banci koristeci korisnikove aktivne kolacice.
2. Kako CSRF napad funkcionise
Zamislite sledeci scenario korak po korak:
- Korisnik se uloguje na
banka.rsi dobija sesijski kolacic - Bez da se odjavi, korisnik posecuje
maliciozni-sajt.com - Maliciozni sajt sadrzi skriveni HTML koji automatski salje zahtev ka banci
- Browser prilaze bankovne kolacice uz taj zahtev jer idu ka
banka.rsdomenu - Banka prima zahtev sa validnim kolacicima i izvrsava akciju
Primer malicioznog koda
Napadac moze ubaciti skrivenu formu na svoj sajt:
<!-- Skrivena forma koja se automatski salje -->
<form action="https://banka.rs/transfer" method="POST" id="csrf-form">
<input type="hidden" name="primalac" value="napadac-racun">
<input type="hidden" name="iznos" value="50000">
<input type="hidden" name="valuta" value="RSD">
</form>
<script>document.getElementById('csrf-form').submit();</script>
Ili cak putem GET zahteva sa img tagom:
<!-- Nevidljiva slika koja salje GET zahtev -->
<img src="https://banka.rs/transfer?primalac=napadac&iznos=50000"
width="0" height="0" style="display:none">
3. CSRF vs XSS — kljucne razlike
| Karakteristika | CSRF | XSS |
|---|---|---|
| Tip napada | Zloupotrebljava poverenje sajta u browser | Ubacuje kod u sajt koji se izvrsava u browseru |
| Potrebna autentifikacija | Da — korisnik mora biti ulogovan | Ne — radi na svim posetiocima |
| Krade podatke? | Ne — forsira akciju | Da — moze citati DOM, kolacice, tokene |
| Izvrsavanje skripte | Ne zahteva JavaScript na ciljnom sajtu | Izvrsava JavaScript u kontekstu sajta |
| Zastita | CSRF tokeni, SameSite kolacici | CSP header, output encoding, sanitizacija |
4. Realni primeri CSRF napada
Gmail CSRF ranjivost (2007)
Istrazivac bezbednosti je 2007. godine otkrio CSRF ranjivost u Gmail-u koja je dozvoljavala napadacu da dodaje email filtere na nalog zrtve. Napadac je mogao da kreira filter koji automatski prosledjuje sve dolazne email-ove na njegovu adresu. Korisnik ne bi ni znao da su mu email-ovi kompromitovani.
Izvor: "Gmail CSRF Security Vulnerability", Petko D. Petkov, 2007
Netflix CSRF napad (2006)
Netflix je 2006. godine imao CSRF ranjivost koja je dozvoljavala napadacu da promeni podatke na korisnickom nalogu — ukljucujuci adresu za dostavu DVD-ova, email i lozinku. Napadac je takodje mogao da dodaje filmove u korisnikov red za gledanje.
Izvor: Netflix Security Advisory, 2006
ING Direct CSRF (2008)
ING Direct banka je imala CSRF ranjivost koja je dozvoljavala napadacu da inicira transfer novca sa racuna zrtve. Napadac je trebalo samo da zna broj racuna, dok bi browser zrtve automatski prilogio autentifikacione kolacice.
5. Metode zastite od CSRF-a
5.1 CSRF tokeni (Synchronizer Token Pattern)
Najsiri koriscena zastita. Server generise jedinstven, nepredvidljiv token za svaku sesiju (ili svaki zahtev) i ubacuje ga u svaku formu. Kada forma stigne nazad, server proverava da li token odgovara.
<!-- Server generise token i ubacuje u formu -->
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token"
value="a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6">
<input type="text" name="primalac">
<input type="number" name="iznos">
<button type="submit">Posalji</button>
</form>
Napadac ne moze da procita token sa drugog domena zahvaljujuci Same-Origin Policy u browser-u.
5.2 SameSite kolacici
Moderan i efikasan pristup. SameSite atribut na kolacicima kontrolise da li browser salje kolacice uz cross-site zahteve:
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnly
| Vrednost | Ponasanje | Preporuka |
|---|---|---|
Strict | Kolacic se nikad ne salje uz cross-site zahteve | Bankarske aplikacije |
Lax | Salje se samo uz top-level GET navigaciju | Vecina sajtova (default u Chrome-u od 2020) |
None | Uvek se salje (staro ponasanje, zahteva Secure) | Samo za cross-site use-case |
5.3 Double Submit Cookie
Server postavlja CSRF token i kao kolacic i kao skriveno polje u formi. Kada zahtev stigne, server proverava da li se vrednosti poklapaju. Napadac moze poslati kolacic (browser ga automatski prilaze), ali ne moze procitati njegovu vrednost da je stavi u formu.
5.4 Origin i Referer header provera
Server moze proveriti Origin ili Referer header da utvrdi odakle zahtev dolazi:
// Node.js middleware za proveru Origin headera
function csrfOriginCheck(req, res, next) {
const origin = req.headers['origin'];
const referer = req.headers['referer'];
const allowedOrigins = ['https://moj-sajt.rs'];
if (req.method !== 'GET') {
if (origin && !allowedOrigins.includes(origin)) {
return res.status(403).json({ error: 'CSRF detected' });
}
if (!origin && referer) {
const refOrigin = new URL(referer).origin;
if (!allowedOrigins.includes(refOrigin)) {
return res.status(403).json({ error: 'CSRF detected' });
}
}
}
next();
}
6. Implementacija u framework-ovima
Django (Python)
Django ima ugradjenu CSRF zastitu koja je podrazumevano ukljucena:
# settings.py — CSRF middleware je podrazumevano aktivan
MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware',
# ...
]
# U template-u koristite {% csrf_token %} tag
# <form method="POST">
# {% csrf_token %}
# ...
# </form>
# Za AJAX zahteve, procitajte token iz kolacica
# i posaljite ga kao X-CSRFToken header
Express.js (Node.js)
const csrf = require('csurf');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
// Konfigurisanje CSRF zastite
const csrfProtection = csrf({ cookie: true });
app.get('/forma', csrfProtection, (req, res) => {
res.render('forma', { csrfToken: req.csrfToken() });
});
app.post('/proces', csrfProtection, (req, res) => {
// Zahtev je validan, CSRF token je proveren
res.send('Uspesno!');
});
Spring Boot (Java)
// Spring Security ukljucuje CSRF zastitu po defaultu
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(
CookieCsrfTokenRepository.withHttpOnlyFalse()
)
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
// U Thymeleaf template-u:
// <input type="hidden" th:name="${_csrf.parameterName}"
// th:value="${_csrf.token}"/>
7. Cesto postavljana pitanja
O: U velikoj meri da, ali ne pokriva sve slucajeve. POST zahtevi iz forme na drugom domenu ce biti blokirani, ali postoje edge slucajevi sa GET zahtevima koji menjaju stanje. Preporuka je kombinovati SameSite sa CSRF tokenima.
O: Ne direktno. CORS kontrolise da li JavaScript na drugom domenu moze citati odgovor, ali ne sprecava slanje zahteva. Browser ce i dalje poslati zahtev (sa kolacicima) — samo nece dozvoliti skripti da procita odgovor.
O: Ako API koristi cookie-based autentifikaciju, da. Ako koristi Authorization header sa Bearer tokenom, CSRF nije moguc jer browser ne salje automatski Authorization header.
8. Reference
- OWASP: Cross-Site Request Forgery (CSRF)
- OWASP CSRF Prevention Cheat Sheet
- CWE-352: Cross-Site Request Forgery (CSRF)
- RFC 7231 — HTTP/1.1 Semantics and Content
- MDN: SameSite cookies
- IBM Cost of a Data Breach Report 2023
CSRF Attacks — Cross-Site Request Forgery
Published: April 8, 2026 · Reading time: 12 min
Table of Contents
1. What is CSRF?
CSRF (Cross-Site Request Forgery), also known as "session riding" or "one-click attack," is a type of web application attack where an attacker tricks a user's browser into executing an unwanted action on a site where the user is currently authenticated.
The key aspect of CSRF is that the attacker doesn't need to know the user's password. The browser automatically sends cookies with every request to a domain, so if a user is logged into their banking site and visits a malicious page, that page can send a request to the bank using the user's active session cookies.
2. How CSRF attacks work
Consider the following step-by-step scenario:
- User logs into
bank.comand receives a session cookie - Without logging out, the user visits
malicious-site.com - The malicious site contains hidden HTML that automatically sends a request to the bank
- The browser attaches the banking cookies to that request since they're going to
bank.com - The bank receives the request with valid cookies and executes the action
Malicious code example
An attacker can embed a hidden form on their site:
<!-- Hidden form that auto-submits -->
<form action="https://bank.com/transfer" method="POST" id="csrf-form">
<input type="hidden" name="recipient" value="attacker-account">
<input type="hidden" name="amount" value="5000">
<input type="hidden" name="currency" value="USD">
</form>
<script>document.getElementById('csrf-form').submit();</script>
Or even via a GET request using an img tag:
<!-- Invisible image that sends a GET request -->
<img src="https://bank.com/transfer?recipient=attacker&amount=5000"
width="0" height="0" style="display:none">
3. CSRF vs XSS — key differences
| Characteristic | CSRF | XSS |
|---|---|---|
| Attack type | Exploits site's trust in the browser | Injects code into the site that runs in the browser |
| Auth required | Yes — user must be logged in | No — works on all visitors |
| Steals data? | No — forces an action | Yes — can read DOM, cookies, tokens |
| Script execution | Doesn't need JS on target site | Executes JS in the site's context |
| Protection | CSRF tokens, SameSite cookies | CSP header, output encoding, sanitization |
4. Real-world CSRF examples
Gmail CSRF vulnerability (2007)
In 2007, a security researcher discovered a CSRF vulnerability in Gmail that allowed an attacker to add email filters to a victim's account. The attacker could create a filter that automatically forwarded all incoming emails to their address. The user would have no idea their emails were compromised.
Source: "Gmail CSRF Security Vulnerability", Petko D. Petkov, 2007
Netflix CSRF attack (2006)
Netflix had a CSRF vulnerability in 2006 that allowed an attacker to modify account details — including DVD delivery address, email, and password. The attacker could also add movies to the user's queue.
Source: Netflix Security Advisory, 2006
ING Direct CSRF (2008)
ING Direct bank had a CSRF vulnerability that allowed attackers to initiate money transfers from victim accounts. The attacker only needed to know the account number, while the victim's browser would automatically attach authentication cookies.
5. Protection methods
5.1 CSRF tokens (Synchronizer Token Pattern)
The most widely used protection. The server generates a unique, unpredictable token for each session (or each request) and embeds it in every form. When the form is submitted, the server verifies the token matches.
<!-- Server generates token and embeds in form -->
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token"
value="a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6">
<input type="text" name="recipient">
<input type="number" name="amount">
<button type="submit">Send</button>
</form>
The attacker cannot read the token from another domain thanks to the browser's Same-Origin Policy.
5.2 SameSite cookies
A modern and effective approach. The SameSite attribute on cookies controls whether the browser sends cookies with cross-site requests:
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnly
| Value | Behavior | Recommendation |
|---|---|---|
Strict | Cookie is never sent with cross-site requests | Banking applications |
Lax | Sent only with top-level GET navigation | Most sites (Chrome default since 2020) |
None | Always sent (old behavior, requires Secure) | Only for cross-site use cases |
5.3 Double Submit Cookie
The server sets the CSRF token both as a cookie and as a hidden form field. When the request arrives, the server checks that the values match. An attacker can send the cookie (browser attaches it automatically), but cannot read its value to put in the form field.
5.4 Origin and Referer header validation
The server can check the Origin or Referer header to determine where the request came from:
// Node.js middleware for Origin header validation
function csrfOriginCheck(req, res, next) {
const origin = req.headers['origin'];
const referer = req.headers['referer'];
const allowedOrigins = ['https://my-site.com'];
if (req.method !== 'GET') {
if (origin && !allowedOrigins.includes(origin)) {
return res.status(403).json({ error: 'CSRF detected' });
}
if (!origin && referer) {
const refOrigin = new URL(referer).origin;
if (!allowedOrigins.includes(refOrigin)) {
return res.status(403).json({ error: 'CSRF detected' });
}
}
}
next();
}
6. Framework implementations
Django (Python)
Django has built-in CSRF protection that is enabled by default:
# settings.py — CSRF middleware is active by default
MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware',
# ...
]
# In templates use {% csrf_token %} tag
# <form method="POST">
# {% csrf_token %}
# ...
# </form>
# For AJAX requests, read the token from the cookie
# and send it as the X-CSRFToken header
Express.js (Node.js)
const csrf = require('csurf');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
// Configure CSRF protection
const csrfProtection = csrf({ cookie: true });
app.get('/form', csrfProtection, (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
app.post('/process', csrfProtection, (req, res) => {
// Request is valid, CSRF token has been verified
res.send('Success!');
});
Spring Boot (Java)
// Spring Security includes CSRF protection by default
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(
CookieCsrfTokenRepository.withHttpOnlyFalse()
)
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
// In Thymeleaf template:
// <input type="hidden" th:name="${_csrf.parameterName}"
// th:value="${_csrf.token}"/>
7. Frequently asked questions
A: Largely yes, but it doesn't cover all cases. POST requests from forms on other domains will be blocked, but there are edge cases with state-changing GET requests. The recommendation is to combine SameSite with CSRF tokens.
A: Not directly. CORS controls whether JavaScript on another domain can read the response, but it doesn't prevent the request from being sent. The browser will still send the request (with cookies) — it just won't let the script read the response.
A: If the API uses cookie-based authentication, yes. If it uses an Authorization header with a Bearer token, CSRF is not possible because the browser doesn't automatically send the Authorization header.
8. References
- OWASP: Cross-Site Request Forgery (CSRF)
- OWASP CSRF Prevention Cheat Sheet
- CWE-352: Cross-Site Request Forgery (CSRF)
- RFC 7231 — HTTP/1.1 Semantics and Content
- MDN: SameSite cookies
- IBM Cost of a Data Breach Report 2023