Search code examples
pythondjangodjango-csrf

CSRF token missing or incorrect even though i have {% csrf_token %} but I use HttpResponse


form.html

<form action='/login/' method = 'post'>
    {% csrf_token %}
    <label>Email: (*)</label><input type='text' name='email' value='' /><br />
    <label>Password: </label><input type='password' name='password' value='' /><br />
    <input type='submit' name='submit' value='Log in' />
</form>

and views.py i use HttpResponse not render_to_response

def login(request):
    success = False
    message = ''

    try:
        emp = Employee.objects.get(email = request.POST['email'])
        if emp.password == md5.new(request.POST['password']).hexdigest() :
            emp.token = md5.new(request.POST['email'] + str(datetime.now().microsecond)).hexdigest()
            emp.save()
            info = serializers.serialize('json', Employee.objects.filter(email = request.POST['email']))
            success = True
            return HttpResponse(json.dumps({'success':str(success).lower(), 'info':info}))
        else:
            message = 'Password wrong!'
            return HttpResponse(json.dumps({'success':str(success).lower(), 'message':message}), status = 401)
    except:
        message = 'Email not found!'
        return HttpResponse(json.dumps({'success':str(success).lower(), 'message':message}), status = 401)

if use render_to_response, i just add RequestContext but HttpResponse, i don't know what to do.

i use Django 1.4
Where's my problem

=========================

My problem is sloved when I change the function that render the HTML :

def homepage(request):
    return render_to_response('index.html')

to

def homepage(request):
    return render_to_response('index.html', context_instance=RequestContext(request))

That's a stupid mistake... thanks...


Solution

  • If you are using ajax to send the form and have included jQuery, you have two possibilities:

    1. Manually add the csrfmiddlewaretoken data to your POST request
    2. Automate CSRF token handling by modifying jQuery ajax request headers

    1. Manually add csrfmiddlewaretoken

    var data = {
        csrfmiddlewaretoken: $('#myForm input[name=csrfmiddlewaretoken]').val(),
        foo: 'bar',
    };
    
    $.ajax({
        type: 'POST',
        url: 'url/to/ajax/',
        data: data,
        dataType: 'json',
        success: function(result, textStatus, jqXHR) {
            // do something with result
        },
    });
    

    2. Automate CSRF token handling

    jQuery(document).ajaxSend(function(event, xhr, settings) {
        function getCookie(name) {
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        function sameOrigin(url) {
            // url could be relative or scheme relative or absolute
            var host = document.location.host; // host + port
            var protocol = document.location.protocol;
            var sr_origin = '//' + host;
            var origin = protocol + sr_origin;
            // Allow absolute or scheme relative URLs to same origin
            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                // or any other URL that isn't scheme relative or absolute i.e relative.
                !(/^(\/\/|http:|https:).*/.test(url));
        }
        function safeMethod(method) {
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
    
        if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    });
    

    But: It is said that modifying the ajax request headers is bad practice. Therefore i'd go with solution number one.

    Source: Cross Site Request Forgery protection: AJAX