Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360
Academy Cross-Site Request Forgery
Intermediate · 20 min

Cross-Site Request Forgery

Learn how forged cross-origin form submissions hijack authenticated sessions and how CSRF tokens stop them.

1 CSRF Mechanics

Cross-Site Request Forgery (CSRF) exploits the browser's automatic inclusion of cookies in cross-origin requests. An attacker's page can submit forms to a different origin — the victim's browser includes their session cookie automatically.

Attack example:

<!-- Attacker's page (evil.com) -->
<form action="https://bank.com/transfer" method="POST" id="csrf">
  <input type="hidden" name="to" value="attacker-account">
  <input type="hidden" name="amount" value="5000">
</form>
<script>document.getElementById("csrf").submit();</script>

When a victim visits evil.com while logged into bank.com, the form auto-submits and the browser automatically includes the bank.com session cookie. The bank sees a valid authenticated request.

What CSRF can do:

  • Transfer money or change account settings
  • Change email/password
  • Delete data or make purchases
  • Any state-changing operation the user is authorized for

2 CSRF Tokens and SameSite Cookies

Two main defenses exist: CSRF tokens (synchronizer token pattern) and SameSite cookie attribute.

CSRF token (synchronizer token pattern):

import secrets

# On form render: generate and store token in session
csrf_token = secrets.token_urlsafe(32)
request.session["csrf_token"] = csrf_token
# Include in form as hidden field

# On form submit: verify token matches
def handle_transfer(request):
    form_token = request.POST.get("csrf_token")
    if not form_token or not hmac.compare_digest(
        form_token, request.session.get("csrf_token", "")
    ):
        return HttpResponse("CSRF validation failed", status=403)

SameSite cookie attribute (modern defense):

response.set_cookie(
    "session",
    session_id,
    samesite="Strict",  # Or "Lax" for GET-safe cross-site navigation
    httponly=True,
    secure=True
)

SameSite=Strict prevents the cookie from being sent on any cross-site request. SameSite=Lax allows top-level navigation GET requests but blocks cross-site POST submissions.

Knowledge Check

0/3 correct
Q1

Why does CSRF work even when the attacker cannot read the victim's cookies?

Q2

What does SameSite=Strict prevent?

Q3

Where should a CSRF token be stored to be validated on the server?

Code Exercise

Add CSRF Token Validation

The transfer endpoint processes POST requests with no CSRF protection. Add CSRF token generation and validation.

python