CSRF Napadi — Cross-Site Request Forgery

Objavljeno: 8. april 2026. · Vreme citanja: 12 min

36%
Web aplikacija ranjivo na CSRF (OWASP)
CWE-352
MITRE klasifikacija
#8
OWASP Top 10 (2013)
$3.4M
Prosecna cena data breach-a (IBM 2023)

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.

Upozorenje: CSRF napad ne krade podatke — on forsira akciju u ime korisnika. To moze ukljucivati transfer novca, promenu email adrese, ili brisanje naloga.

2. Kako CSRF napad funkcionise

Zamislite sledeci scenario korak po korak:

  1. Korisnik se uloguje na banka.rs i dobija sesijski kolacic
  2. Bez da se odjavi, korisnik posecuje maliciozni-sajt.com
  3. Maliciozni sajt sadrzi skriveni HTML koji automatski salje zahtev ka banci
  4. Browser prilaze bankovne kolacice uz taj zahtev jer idu ka banka.rs domenu
  5. 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">
Napomena: Zato je izuzetno vazno da GET zahtevi nikada ne menjaju stanje servera (state-changing operations). Ovo je osnovno pravilo HTTP specifikacije (RFC 7231).

3. CSRF vs XSS — kljucne razlike

KarakteristikaCSRFXSS
Tip napadaZloupotrebljava poverenje sajta u browserUbacuje kod u sajt koji se izvrsava u browseru
Potrebna autentifikacijaDa — korisnik mora biti ulogovanNe — radi na svim posetiocima
Krade podatke?Ne — forsira akcijuDa — moze citati DOM, kolacice, tokene
Izvrsavanje skripteNe zahteva JavaScript na ciljnom sajtuIzvrsava JavaScript u kontekstu sajta
ZastitaCSRF tokeni, SameSite kolaciciCSP 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.

Lekcija: Cak i najvece kompanije (Google, Netflix, banke) su bile ranjive na CSRF. Nijedan sajt nije previše veliki ili previše siguran da bi ignorisao ovu pretnju.

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
VrednostPonasanjePreporuka
StrictKolacic se nikad ne salje uz cross-site zahteveBankarske aplikacije
LaxSalje se samo uz top-level GET navigacijuVecina sajtova (default u Chrome-u od 2020)
NoneUvek 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

P: Da li SameSite=Lax potpuno stiti od CSRF-a?
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.
P: Da li CORS stiti od CSRF-a?
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.
P: Da li su API-ji ranjivi na CSRF?
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

Skenirajte svoj sajt besplatno →

CSRF Attacks — Cross-Site Request Forgery

Published: April 8, 2026 · Reading time: 12 min

36%
Web apps vulnerable to CSRF (OWASP)
CWE-352
MITRE classification
#8
OWASP Top 10 (2013)
$3.4M
Average data breach cost (IBM 2023)

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.

Warning: CSRF doesn't steal data — it forces an action on behalf of the user. This can include money transfers, email address changes, or account deletion.

2. How CSRF attacks work

Consider the following step-by-step scenario:

  1. User logs into bank.com and receives a session cookie
  2. Without logging out, the user visits malicious-site.com
  3. The malicious site contains hidden HTML that automatically sends a request to the bank
  4. The browser attaches the banking cookies to that request since they're going to bank.com
  5. 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">
Note: This is why GET requests must never perform state-changing operations. This is a fundamental HTTP specification rule (RFC 7231).

3. CSRF vs XSS — key differences

CharacteristicCSRFXSS
Attack typeExploits site's trust in the browserInjects code into the site that runs in the browser
Auth requiredYes — user must be logged inNo — works on all visitors
Steals data?No — forces an actionYes — can read DOM, cookies, tokens
Script executionDoesn't need JS on target siteExecutes JS in the site's context
ProtectionCSRF tokens, SameSite cookiesCSP 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.

Lesson: Even the largest companies (Google, Netflix, banks) have been vulnerable to CSRF. No site is too big or too secure to ignore this threat.

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
ValueBehaviorRecommendation
StrictCookie is never sent with cross-site requestsBanking applications
LaxSent only with top-level GET navigationMost sites (Chrome default since 2020)
NoneAlways 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

Q: Does SameSite=Lax fully protect against CSRF?
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.
Q: Does CORS protect against CSRF?
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.
Q: Are APIs vulnerable to CSRF?
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

Scan your site for free →