7
votes

Are forms that use the POST method required to have CSRF protection? I'm following a book and the code examples throw 403 errors. I did some searching and it seems as if I need to enable CSRF in all my forms.

My questions are:

  1. Does Django now require that all POST forms be protected from CSRF?

  2. All I need to do to accomplish this is add 'django.middleware.csrf.CsrfViewMiddleware', return render_to_response(template,dictionary,context_instance=RequestContext(request), and add '{% csrf_token %}' in the corresponding form? Am I missing anything here?

When I do this, the form works fine. When any of these pieces are missing, it fails to 403. I just want to make sure I'm doing it RIGHT. :)

Thanks in advance.

edit:

For some reason this code doesn't make sense to me but it doesnt return any error. Please ignore the primitive validation as I haven't gotten to the section of the book where it shows the more efficient way to do it yet.

def contact(request):
    errors = []

    if request.method == 'POST':
        if not request.POST.get('subject',''):
            errors.append('Enter a subject')
        if not request.POST.get('message',''):
            errors.append('Enter a message')
        if request.POST.get('email', '') and '@' not in request.POST['email']:
            errors.append('Enter a valid email address')
        if not errors:
            send_mail(
                request.POST['subject'],
                request.POST['message'],
                request.POST.get('email', '[email protected]'), ['[email protected]'],)
            return HttpResponseRedirect('/contact/thanks/')

    return render_to_response('contact_form.html', { 'errors': errors }, context_instance=RequestContext(request))

My issue is with the very last line of this view function. It is only called if the request.method != POST. This seems completely wrong to me. Shouldn't I be calling "context_instance=RequestContext(request)" when it's doing a POST?

1

1 Answers

13
votes

POST should be used for sensitive information, such as passwords, and django requires securing it with csrf_token; GET should be used for bookmarkable stuff which doesn't need to be secured, like searches. You ARE doing it RIGHT.

EDIT

You shouldn't be calling context_instance=RequestContext(request) when it's doing a POST, you should be calling it regardless of the request type. Look at it like this:

  • Is it a POST? this means the form was submitted. we validate the form, and redirect the user to another page if the form is OK, or show the form again to the user, with the errors.
  • Is it a GET? this means the form was not submitted, but other stuff is happening which we don't care about (some referrer link or other stuff). Show the form anyway

Actions in italic are done by the last return, regardless of the if.