Intermediate Web — OWASP Top 10

CSRF — Forging Authenticated Requests

Cross-Site Request Forgery (CSRF) exploits the trust a server places in an authenticated user’s browser. The attacker crafts a malicious page that, when visited, fires a request to the target using the victim’s cookies already stored in the browser.

How It Works

1. Victim logs in to bank.example.com — session cookie stored in browser.
2. Victim visits evil.example (link sent by email or chat).
3. evil.example contains a hidden form that POSTs to bank.example.com/transfer.
4. Browser automatically includes the session cookie.
5. Bank processes the transfer as if the victim initiated it.

Payload Example (Fictional Environment)

<!-- evil.example/trap.html -->
<form id="f" action="https://bank.example.com/transfer" method="POST">
  <input name="to"     value="attacker-account">
  <input name="amount" value="5000">
</form>
<script>document.getElementById('f').submit();</script>

A GET-based attack can be even simpler with an <img> tag:

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

Why Cookies Alone Are Not Enough

The browser sends cookies automatically with every cross-origin request to the correct domain. The victim’s session is valid — the server cannot distinguish a legitimate request from a forged one without extra controls.

Prevention — CSRF Token

Generate an unpredictable per-session token. Include it in every form and validate it server-side.

// Generation (PHP)
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));

// In the HTML form
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">

// Server-side validation
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
    http_response_code(403);
    exit('CSRF detected');
}
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
  • SameSite=Strict: cookie not sent on any cross-site request.
  • SameSite=Lax: sent only on top-level navigations (links), not on cross-site POSTs.

SameSite is the simplest and most effective defense for modern browsers.

Prevention — Verify Origin/Referer

# Django / any framework
origin = request.headers.get('Origin', '')
if origin not in ALLOWED_ORIGINS:
    return HttpResponseForbidden()

Complementary Defenses

  • Re-authenticate for sensitive actions (transfers, password changes).
  • JSON APIs with Content-Type: application/json — HTML forms cannot set that header cross-origin.
  • Double Submit Cookie: token in both cookie and body, compared server-side.
  • Modern frameworks (Laravel, Django, Rails) enable CSRF protection by default — do not disable it.

What CSRF Cannot Do

CSRF cannot read server responses (same-origin policy blocks that). The attack acts, it does not eavesdrop — to steal data use XSS, not CSRF.