2

I have a form in my html:

<form id="form" action="" method="post"> {% csrf_token %}
   <div>{{form.input1}}</div>
   <div>{{form.input2}}</div>
   <div>{{form.input3}}</div>
   <input type="submit" class="btn" name="submit" value="submit">
</form>

and in my urls.py:

urlpatterns = [
    url(r'^$', views.MyView.as_view(success_url='/'), name='index'),
]

and sometimes when I hit submit, the csrf token gets triggered and says csrf token missing or incorrect.

First of all how is this possible? The doc says:

This should usually only be seen when there is a genuine Cross Site Request Forgery, or when, due to a programming error, the CSRF token has not been included with a POST form.

From what I see it's implemented correctly.

The error message further says

  • Your browser is accepting cookies

it does

  • The view function passes a request to the template's render method

According to the doc I have that.

  • In the template there is a {%csrf_token%} template tag inside each POST form that targets an internal URL

it is indeed, but that's the whole point of having a csrf token right?

  • If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.

According to the doc this is activated by default.

So why does it trigger sometimes (very rarely)?

Tom
  • 2,545
  • 5
  • 31
  • 71

2 Answers2

4

Since you say that the error only occurs sometimes, I think the problem might be that you opened the page with the form, logged in on another tab, then submitted the form.

This causes an error because the csrf token is updated when you log in. Unfortunately, you can't really do anything about this.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • actually this was the correct answer as I just found out. Is there nothing to do? – Tom Mar 11 '16 at 22:57
  • 1
    The CSRF token is rotated for security purposes. I'm not aware of anything you can do to avoid the csrf errors for the user. – Alasdair Mar 12 '16 at 10:35
2

Are you rendering your form dynamically or something like that? Django only replaces {% csrf_token %} with the hidden input field and injects csrftoken cookie when that tag is present in the template from the beginning.

First try decorating your views with:

from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def index(request):
    return render(request, 'index.html')

This will always inject the cookie.

If you really are manipulating the form dynamically you need to use csrftoken cookie to retrieve the csrf token manually and then submit it along the form either using hidden field (extra request param) or a header, as stated in the docs.

serg
  • 109,619
  • 77
  • 317
  • 330
  • We had a similar issue which only occurred on safari, and using the decorator fixed it. – user2390182 Mar 10 '16 at 20:20
  • ok thanks, so I just put the decorator anywhere in my views? I did it. Is there any chance of finding out if it works, other than just waiting to see if it will randomly occure again? – Tom Mar 10 '16 at 20:26
  • @PaulBernhardWagner To test if decorator works you can inspect cookies on a view that doesn't have `{% csrf_token %}` and it shouldn't have the cookie without the decorator. To test if it helps in your case you would need to reproduce a problem first somehow, can't tell without it. If that really is what causes the issue then yes, you would need to decorate all views with it, or at least those that submit requests. – serg Mar 10 '16 at 20:38