Skip to content

3. CSRF

Can an Attacker Reuse the CSRF Token?

No, because CSRF protection relies on both the token and the user’s session authentication.

Even if an attacker captures the CSRF token (e.g., via XSS), they still cannot forge a request unless:

  1. The victim is logged into the website.
  2. The request is sent from the victim’s browser with their session cookie.

Why This Attack Fails

  1. Tokens Are Session-Specific

    • CSRF tokens are tied to a user’s session and cannot be used by another user.
    • If an attacker copies the CSRF token from their own session and sends it, Django rejects it.
  2. Same-Site Cookie Attribute (Django 3.1+)

    • Django sets the CSRF cookie with SameSite=Lax (or Strict if configured).
    • This prevents CSRF attacks by blocking cross-origin requests unless the user interacts directly with the site.
  3. Referer Header Validation (Enabled by Default)

    • Django checks the Referer header to ensure requests come from the same origin.
    • If an attacker submits a form from another site, the request is rejected.

Possible Ways an Attacker Might Try to Bypass CSRF Protection

Attack MethodWhy It Fails
Stealing the CSRF Token (e.g., via XSS)Useless unless the attacker also controls the victim’s session.
Submitting a Form with a Stolen CSRF TokenIf the session cookie does not match, Django rejects it.
Sending a Fake Request via CURL/PostmanNeeds a valid session cookie (which cannot be stolen via CSRF).
Forged Requests from Another Site (CSRF Attack)Django blocks cross-origin requests with CSRF protection.

How to Make CSRF Protection Even Stronger?

  1. Enable CSRF_COOKIE_SECURE (Requires HTTPS)

    • Ensures CSRF cookies are only sent over secure connections.
    CSRF_COOKIE_SECURE = True # Enforces HTTPS for CSRF tokens
  2. Use SameSite=Strict for Cookies (If applicable)

    • Prevents cookies from being sent in cross-site requests.
    CSRF_COOKIE_SAMESITE = 'Strict'
  3. Enable CSRF_TRUSTED_ORIGINS for API Calls

    • If you need to allow requests from other domains (e.g., an API client).
    CSRF_TRUSTED_ORIGINS = ['https://your-frontend.com']
  4. Use HTTP Headers for APIs Instead of CSRF Tokens

    • For APIs, use authentication tokens (JWT, OAuth, etc.) instead of CSRF.
    from django.views.decorators.csrf import csrf_exempt
    @csrf_exempt
    def my_api_view(request):
    return JsonResponse({"message": "CSRF disabled for this API"})

Conclusion

✅ Django’s CSRF protection is secure against token reuse.
✅ Even if an attacker steals a token, they still need the session cookie.
Additional security (HTTPS, SameSite cookies, referer validation) makes attacks even harder.