- What Is CSRF?
- CSRF stands for Cross-Site Request Forgery.
- It is a type of security vulnerability where an attacker tricks a victim’s browser into submitting unintended requests to a trusted website where the user is authenticated.
- Example:
- User is logged into
bank.com
- User visits a malicious website that makes a
POST request to bank.com/transfer
- The browser includes session cookies automatically — and the bank thinks the user intended it!
- Why CSRF Works (Origin & Exploit Mechanism)
- Browsers automatically include session cookies with every request to a site — regardless of the source.
- Common attack vectors:
- Auto-submitted hidden forms
- Image tags:
<img src="https://target.com/delete?id=5">
- JavaScript-based cross-domain fetches (if CORS not properly restricted)
- Because the server uses the session cookie to identify the user, it cannot distinguish a legitimate request from a forged one — unless CSRF protection is applied.
- How CSRF Tokens Work
- The main prevention strategy is the use of
CSRF tokens.
- A CSRF token is:
- a random, cryptographically secure string
- generated by the server per session or per request
- embedded into HTML forms or headers
- How it works:
- User loads a form → receives a CSRF token
- User submits the form → token is sent back to server
- Server verifies the token is valid for this session
- If the token is missing or incorrect, the request is blocked.
- Example: How Django Prevents CSRF
- Django has built-in CSRF protection enabled by default.
- It uses:
- a middleware:
django.middleware.csrf.CsrfViewMiddleware
- a per-session token stored in the user's session or cookie
- a validation check for every
POST / PUT / PATCH / DELETE request
- You must include a CSRF token in every
POST form:
<form method="post">
{% csrf_token %}
<input name="name" />
</form>
- This generates:
<input type="hidden" name="csrfmiddlewaretoken" value="AbCd123..." />
- CSRF Protection in Django Views and APIs
- Template-based views are protected automatically if you use
{% csrf_token %}.
- Function-based views require no special action unless CSRF checks are manually disabled.
- AJAX/Fetch requests must send the token in a header:
fetch('/api/update/', {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
- Set the token from the cookie:
function getCookie(name) {
const match = document.cookie.match(new RegExp(name + '=([^;]+)'));
return match ? match[1] : null;
}
- Disabling CSRF in Django (Not Recommended)
- You can disable CSRF checks using decorators:
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def public_webhook(request):
...
- This should be used with caution — only for trusted endpoints (e.g. webhooks or internal APIs).
- Never disable CSRF for forms or authenticated user endpoints.
- Common CSRF Protection Strategies
- Always use POST for state-changing operations
- Include CSRF tokens in all non-idempotent requests
- Use
SameSite=Lax or Strict cookie policies
- Validate HTTP Referer headers (optional extra check)
- Enable HTTPS to avoid token interception
- CSRF vs XSS
- CSRF exploits trust in the user's browser
- XSS exploits trust in user-supplied content
- They are different but often combined:
- XSS can be used to steal a CSRF token
- CSRF can be used to abuse XSS-injected sessions
- Verifying CSRF Protection Works