Search code examples
djangoiframecsrf

Django: CSRF Cookie not set in iframe -- workaround without csrf exempt


My project is deploying iframes on several 3rd party sites, that are all known and registered within the django application.

In these iframes, users can trigger some ajax-form events. Opening the site directly, everything works fine. If I open the 3rd party site, containing the iframe, django is throwing an error after firing the ajax event (403), saying that CSRF failed.

In the form I used {% csrf_token %} which is set in the html. However it does not set the corresponding cookie, when calling the site through the iframe (found out both using inspection mode in browser).

I do know that I could use a decorator @csrf_exempt, but that will disable csrf-protection all in one, which I don´t want to do.

So my questions are:

  1. Why does django not set the CSRF Cookie, when the whole page is loaded through an iframe?
  2. Is it possible to get django to set the cookie OR is it possible to only exempt the known urls from csrf?
  3. Is there a way I dont see?

Thanks a lot for your time! :)


Solution

  • I was dealing with the same issue, and the answer by Midas Gossye didn't work for me. My solution was to make the following edits in settings.py to get Django to set the CSRF cookie, when the site is in an iframe.

    1. Set CSRF_COOKIE_SAMESITE = "None", because you want the CSRF cookie to be sent from your site to the site that has it in an iframe (source)
    2. Make sure Django marks the CSRF cookie as secure, with CSRF_COOKIE_SECURE = True. This means that browsers will make sure this cookie is sent over HTTPS only (source). You should have this because it's more secure, and future versions of browsers will only send cookies with a SameSite=None if it is also marked as Secure.
    3. You don't need to set the CSRF_TRUSTED_ORIGINS like one of the previous answers suggests, in fact arguably you shouldn't because of security reasons. This is because if a user is using your site through an iframe, the POST requests are still coming from your site, not from some other server. This setting is only needed if POST requests will come from a site on another server (source)

    You will probably have to clear the cookies that you had on your Django site (should include the csrftoken cookie), and reload and check that the new csrftoken is marked as "Secure" and doesn't have a "SameSite".

    Now, the csrftoken cookie should be set when a 3rd party page has your page in an iframe (you can confirm by having your page use Javascript to print the csrftoken cookie), and you should be able to make successful POST requests from your iframe-d Django site.