4

Opening a Django 1.10 application in a second browser tab refreshes the CSRF token. This breaks all forms in the first tab -- i.e., previously opened forms can no longer be submitted because the old CSRF token is now invalid.

How do I avoid this behavior?

Step-by-step example:

  1. User is viewing a form in Tab A.
  2. User opens the application in Tab B.
  3. User returns to Tab A and attempts to submit the form.
  4. Error: Forbidden (403). CSRF verification failed. Request aborted.

Some details:

I would really like to permit multi-tab browsing in the application.

The Django 1.10 release notes document a change to the CSRF mechanism:

To protect against BREACH attacks, the CSRF protection mechanism now changes the form token value on every request (while keeping an invariant secret which can be used to validate the different tokens).

Django's 1.9 CSRF documentation has a really good description of the usability problem. This paragraph has been removed in the 1.10 CSRF documentation, but it seems to describe the exact problem I'm encountering:

Why not use a new token for each request?

Generating a new token for each request is problematic from a UI perspective because it invalidates all previous forms. Most users would be very unhappy to find that opening a new tab on your site has invalidated the form they had just spent time filling out in another tab or that a form they accessed via the back button could not be filled out.

tino
  • 4,780
  • 5
  • 24
  • 30
  • This is really interesting. Since it's undocumented how to bypass this behaviour, I suggest you ask this on Django's IRC channel. You'll find some Django core developers there who might be able to answer. – xyres Apr 08 '17 at 17:45
  • Thanks @xyres, I'll give that a try. – tino Apr 08 '17 at 21:40

1 Answers1

-2

If you are using the @csrf_protect decorator in your views try using the @csrf_exempt decorator instead.

Before views.py:

    from django.views.decorators.csrf import csrf_protect

    @csrf_protect
    def view(request):
         # Render Something

After views.py:

    from django.views.decorators.csrf import csrf_exempt

    @csrf_exempt
    def view(request):
         # Render Something

Sorry for the late Reply. Better late than never I hope.