Django CSRF Protection Issue

Question:

I’ve just started building an API with Django for the first time and I’ve run into an issue while trying to test an endpoint with Postman. When I send a POST request to the endpoint http://localhost:8000/arithmetic/ containing the following JSON:

{
  "expression": "1 + 2 × 3"
}

I get the following response:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta name="robots" content="NONE,NOARCHIVE">
    <title>403 Forbidden</title>
    <style type="text/css">
        html * {
            padding: 0;
            margin: 0;
        }

        body * {
            padding: 10px 20px;
        }

        body * * {
            padding: 0;
        }

        body {
            font: small sans-serif;
            background: #eee;
            color: #000;
        }

        body>div {
            border-bottom: 1px solid #ddd;
        }

        h1 {
            font-weight: normal;
            margin-bottom: .4em;
        }

        h1 span {
            font-size: 60%;
            color: #666;
            font-weight: normal;
        }

        #info {
            background: #f6f6f6;
        }

        #info ul {
            margin: 0.5em 4em;
        }

        #info p,
        #summary p {
            padding-top: 10px;
        }

        #summary {
            background: #ffc;
        }

        #explanation {
            background: #eee;
            border-bottom: 0px none;
        }
    </style>
</head>

<body>
    <div id="summary">
        <h1>Forbidden <span>(403)</span></h1>
        <p>CSRF verification failed. Request aborted.</p>


    </div>

    <div id="info">
        <h2>Help</h2>

        <p>Reason given for failure:</p>
        <pre>
    CSRF token from the &#x27;X-Csrftoken&#x27; HTTP header has incorrect length.
    </pre>


        <p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when
            <a href="https://docs.djangoproject.com/en/4.1/ref/csrf/">Django’s
                CSRF mechanism</a> has not been used correctly. For POST forms, you need to
            ensure:</p>

        <ul>
            <li>Your browser is accepting cookies.</li>

            <li>The view function passes a <code>request</code> to the template’s <a
                    href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a>
                method.</li>

            <li>In the template, there is a <code>{% csrf_token
    %}</code> template tag inside each POST form that
                targets an internal URL.</li>

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

            <li>The form has a valid CSRF token. After logging in in another browser
                tab or hitting the back button after a login, you may need to reload the
                page with the form, because the token is rotated after a login.</li>
        </ul>

        <p>You’re seeing the help section of this page because you have <code>DEBUG =
  True</code> in your Django settings file. Change that to <code>False</code>,
            and only the initial error message will be displayed. </p>

        <p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
    </div>

</body>

</html>

I am unsure how to resolve this issue so that I can test my endpoint.

Here is my code so far:

Within the arithmetic app:

views.py:

import json
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse

# Create your views here.


def parse_request(str):
    if '×' in str:
        str = str.replace('×', '*')

    if '÷' in str:
        str = str.replace('÷', '/')


def calculate(request):
    if request.method == 'POST':
        # parse the json object
        body = json.loads(request.body)

        expression = body['expression']

        return JsonResponse({
            'response': expression
        })
    else:
        return JsonResponse({
            'error': 'invalid request method'
        })

urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.calculate)
]

And my main projects urls.py looks like this:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('arithmetic/', include('arithmetic.urls'))
]

The idea is to connect this too a React frontend that I’ve already developed but I want to test the endpoint on its own to ensure its working before I try to connect it to the frontend.

Any help or guidance would be greatly appreciated.

Asked By: ben_11

||

Answers:

The fastest way to solve this problem is by using Django’s csrf_exempt function to disable CSRF protection for your view.

from django.views.decorators.csrf import csrf_exempt

urlpatterns = [path('', csrf_exempt(views.calculate))]

You can as well use the decorator on your view:

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def calculate(request):
    if request.method == 'POST':
        # parse the json object
        body = json.loads(request.body)

        expression = body['expression']

        return JsonResponse({
            'response': expression
        })
    else:
        return JsonResponse({
            'error': 'invalid request method'
        })

You can also remove the middleware completely from the config file, this would disable the CSRF protection for all the endpoints. From the config file, remove this line:

django.middleware.csrf.CsrfViewMiddleware

NOTE: This is not recommended for most cases, as it leaves your API vulnerable to CSRF attacks.

Answered By: Harith
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.