4

I've encountered the following situation (using Django1.4 and jQuery 1.7.1) which I would like to understand: I submit a form via jQuery 'ajax' function and before this request finishes I click another element which submits the same form but using the jQuery 'submit' function. The response I get - 403, CSRF verifcation failed. Now, of course, to prevent this error it suffices to disable multiple simultaneous submits(they work fine on their own), but this doesn't help to understand where that specific error comes from.

Can anyone explain this? The csrf token is generated once per session so it cannot be some kind of csrf mismatch for the latter request. Does this have something to do with the way jQuery handels requests?

fjern
  • 41
  • 5
  • the jQuery 'submit' works if you do it by itself instead of concurrently with the ajax submit? – Anentropic Jul 23 '12 at 16:22
  • Is your ajax [properly](https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax) send POST. And can you provide exact error message because in sources I didnt see your error `REASON_NO_REFERER = "Referer checking failed - no Referer." REASON_BAD_REFERER = "Referer checking failed - %s does not match %s." REASON_NO_CSRF_COOKIE = "CSRF cookie not set." REASON_BAD_TOKEN = "CSRF token missing or incorrect."` – b1_ Jul 23 '12 at 19:33
  • @Anentropic: Yes, the submit works when done separately. – fjern Jul 25 '12 at 15:36
  • @b1-: The exact message is: CSRF token missing or incorrect. – fjern Jul 25 '12 at 15:36
  • @fjern little research in my answer.Use PyCharm for debuging – b1_ Jul 25 '12 at 19:39

2 Answers2

0

I think problem in your code. Just read django code


Error catched in this block.

if not constant_time_compare(request_csrf_token, csrf_token):
            logger.warning('Forbidden (%s): %s',
                           REASON_BAD_TOKEN, request.path,
                extra={
                    'status_code': 403,
                    'request': request,
                }
            )
            return self._reject(request, REASON_BAD_TOKEN)

So you front end script send csrf_token which and cookies (which send browser) are not equal


Next code work

tpl

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>

<a href="javascript:" class="req1">req1</a>
<a href="javascript:" class="req2">req2</a>
<br>

<form id="foo" action="" method="POST">{% csrf_token %}
    {{ form.as_p }}
    <input type="submit">
</form>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
    $(document).ready(function(){

        $('.req2').click(function(){
            var form1 = $.post( '', $('#foo').serialize(), function(data){console.log(data)} );
        })

        $('.req1').click(function(){
            var form1 = $.post( '', $('#foo').serialize(), function(data){console.log(data)} );
        })
    })
</script>
</body>
</html>

view

from django import forms
from django.http import HttpResponse

from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect


class TestForm(forms.Form):
    test_field = forms.CharField()


@csrf_protect
def home(request):
    if request.method == 'POST':
        form = TestForm(request.POST)
        if form.is_valid():
            return HttpResponse('all ok')
    else: form = TestForm()

    return render(request,
        'page.html',
            {
            'form': form,
             },
    )
b1_
  • 2,069
  • 1
  • 27
  • 39
0

Problem solved - I missed the fact that the js script responsible for the ajax call set the 'disabled' attribute on the form inputs (including the csrf token) in the beforeSend function - such disabled attrs are not sent in POST.

fjern
  • 41
  • 5