"CSRF-Token fehlt oder ist falsch" beim Posten von Parametern über AJAX in Django


71

Ich versuche Parameter wie zu posten

 jQuery.ajax(
        {
            'type': 'POST',
            'url': url,
            'contentType': 'application/json',
            'data': "{content:'xxx'}",
            'dataType': 'json',
            'success': rateReviewResult 
        }
    );

Forbidden 403. CSRF verification failed. Request aborted. Ich verwende jedoch Django return 'django.middleware.csrf.CsrfViewMiddleware'und konnte nicht herausfinden, wie ich dieses Problem verhindern kann, ohne die Sicherheit zu beeinträchtigen.


Antworten:


107

Sie können AJAX-Post-Anfragen auf zwei verschiedene Arten stellen:

  1. Um Ihrer Ansicht mitzuteilen, dass das csrf-Token nicht überprüft werden soll. Dies kann mit einem Dekorateur @csrf_exemptwie folgt erfolgen:

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def your_view_name(request):
        ...
    
  2. Um ein csrf-Token in jede AJAX-Anforderung einzubetten, kann es für jQuery sein:

    $(function () {
        $.ajaxSetup({
            headers: { "X-CSRFToken": getCookie("csrftoken") }
        });
    });
    

    Wo die getCookieFunktion csrf-Token von Cookies abruft. Ich benutze die folgende Implementierung:

    function getCookie(c_name)
    {
        if (document.cookie.length > 0)
        {
            c_start = document.cookie.indexOf(c_name + "=");
            if (c_start != -1)
            {
                c_start = c_start + c_name.length + 1;
                c_end = document.cookie.indexOf(";", c_start);
                if (c_end == -1) c_end = document.cookie.length;
                return unescape(document.cookie.substring(c_start,c_end));
            }
        }
        return "";
     }
    

    Außerdem hat jQuery ein Plugin für den Zugriff auf Cookies.

    // set cookie
    $.cookie('cookiename', 'cookievalue');
    // read cookie
    var myCookie = $.cookie('cookiename');
    // delete cookie
    $.cookie('cookiename', null);
    

7
Es ist wichtig zu beachten, dass es X-CSRFTokenund nicht X-CSRF-Tokendas ist, was auch häufig verwendet wird
shangxiao

3
Die Verwendung von csrf_exemptDecorator kann zu Sicherheitsproblemen führen, da der Middleware-Schutz deaktiviert wird.
J punto Marcos

Da sich js in einer getrennten Datei befindet und {{ csrf_token }}die erste Option nicht rendern kann, wurde mein Problem gelöst.
Alex Jolig

51

Der einfachste Weg, den ich gefunden habe, besteht darin, den {{csrf_token}}Wert in die Daten aufzunehmen:

jQuery.ajax(
    {
        'type': 'POST',
        'url': url,
        'contentType': 'application/json',
        'data': {
            'content': 'xxx',
            'csrfmiddlewaretoken': '{{ csrf_token }}',
        },
        'dataType': 'json',
        'success': rateReviewResult 
    }
);

5
Was ist, wenn Ihr JavaScript nicht von Django verarbeitet wird? Ich schätze, du wärst wirklich den Bach hinauf.
Naftuli Kay

4
In der ursprünglichen Frage wurde angegeben, dass sie 'django.middleware.csrf.CsrfViewMiddleware' verwenden und Django den Fehler zurückgibt. Ich denke, es ist ziemlich sicher anzunehmen, dass Django die Ajax-Anfrage verarbeitet.
Jerrykan

7
Das Problem ist, dass Django nicht die JS, sondern nur die HTML-Ansichten als Vorlage verwendet.
Naftuli Kay

4
dann tun Sie dies in der base.htmlwindow.csrftoken="{{csrftoken}}";
airtonix

2
Er kann eine csrf-Token-Eingabe in HTML hinzufügen und jquery verwenden, um dieses Token abzurufen, wenn js nicht von django verarbeitet wird. füge {{ csrf_token }}das Formular hinzu und erhalte den Wert von csrf_token = $('input[name="csrfmiddlewaretoken"]').val();und data = {'para1': 'para1_value', csrfmiddlewaretoken: csrf_token};
gib

23

Ich habe eine Weile gebraucht, um zu verstehen, was ich mit dem Code machen soll , den Daniel gepostet hat. Aber eigentlich müssen Sie es nur am Anfang der Javascript-Datei einfügen.

Für mich ist die bisher beste Lösung:

  1. Ein ... kreieren csrf.js Datei

  2. Fügen Sie den Code in das Feld eincsrf.js Datei ein

  3. Verweisen Sie auf den Code in der Vorlage, die Sie benötigen

    <script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script>
    

Beachten Sie, dass STATIC_PREFIX/js/csrf.jsauf meine Datei verweist. Ich lade tatsächlich die STATIC_PREFIXVariable mit {% get_static_prefix as STATIC_PREFIX %}.


Erweiterter Tipp: Wenn Sie Vorlagen verwenden und etwas haben, von base.htmldem aus Sie sich erweitern, können Sie von dort aus einfach auf das Skript verweisen, und Sie müssen sich in den restlichen Dateien keine Sorgen mehr machen. Soweit ich weiß, sollte dies auch kein Sicherheitsproblem darstellen.


3
Das hat mir stundenlange Hacks erspart. Einfacher und pythonischer Weg direkt aus der Django-Dokumentation.
Pratyush

1
Damit the codemeinen Sie genau jedes einzelne Zeichen im grünen Hintergrund? Ich kopiere, füge das ein und tue, was du gesagt hast, erhalte aber immer noch einen verbotenen Fehler. Vielleicht haben sich die Dinge geändert?
Philip007

@ Philip007, ja, der grüne Hintergrund. Sie haben das Dokument für Django 1.5 geändert , aber ich sehe keinen wirklichen Unterschied in den resultierenden Codes. Sie geben nur eine längere Erklärung und die Möglichkeit, jQuery zu verwenden.
toto_tico

@ Phillip007, sind u sicher auf die richtige js Datei , die Sie zeigen src="{{ STATIC_PREFIX }}js/csrft.js". Beachten Sie, dass STATIC_PREFIX eine Variable ist. Ich setze diese Variable mit {% get_static_prefix as STATIC_PREFIX %}. Stellen Sie jedoch sicher, dass das srcauf die richtige Stelle zeigt.
toto_tico

1
Haha danke. Das habe ich von Anfang an bemerkt. In meinem Fall kein Schuldiger :) Ich habe das Problem mit dem jQuery-Plugin "jQuery-cookie" gelöst. Es ist so viel einfacher für mich zu verstehen.
Philip007

12

Einfach und kurz

$.ajaxSetup({
  headers: { "X-CSRFToken": '{{csrf_token}}' }
});

ODER

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
  beforeSend: function(xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", '{{csrf_token}}');
    }
  }
});

docs


einfach und schön
Shashishekhar Hasabnis

8

Mangels einer einfachen Antwort müssen Sie nur den Header X-CSRFTokenzur Ajax-Anfrage hinzufügen, die im Cookie enthalten ist csrftoken. JQuery macht keine Cookies (aus irgendeinem Grund) ohne Plugin, also:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

und die minimale Codeänderung ist:

$.ajax({
  headers: { "X-CSRFToken": $.cookie("csrftoken") },
  ...
});

2
Tausend Stimmen Mann ..... Ich frage mich immer, warum die Leute einfach keine einfache Antwort wie diese geben können !!
NoobEditor

4

Ich habe gestern das gleiche Problem bekommen und dachte, es würde den Leuten helfen, wenn es eine einfache Möglichkeit gäbe, damit umzugehen. Deshalb habe ich ein jQuery-Plugin dafür geschrieben: jquery.djangocsrf . . Anstatt das CSRF-Token in jeder Anforderung hinzuzufügen, hängt es sich an das AjaxSend jQuery-Ereignis an und fügt das Client-Cookie in einen Header ein.

So verwenden Sie es:

1- schließen Sie es ein:

<script src="path/to/jquery.js"></script>
<script src="path/to/jquery.cookie.js"></script>
<script src="path/to/jquery.djangocsrf.js"></script>

2- Aktivieren Sie es in Ihrem Code:

$.djangocsrf( "enable" );

Django fügt das Token immer in ein Cookie ein, wenn Ihre Vorlage verwendet wird {% csrf_token %}. Verwenden Sie den @ensure_csrf_cookieDekorator , um sicherzustellen, dass es immer hinzugefügt wird, auch wenn Sie das spezielle Tag in Ihrer Vorlage nicht verwenden :

from django.views.decorators.csrf import ensure_csrf_cookie

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

Hinweis: Ich verwende Django 1.6.2.


4

Vielen Dank an alle für alle Antworten. Ich benutze Django 1.5.1. Ich bin etwas spät zur Party, aber jetzt geht es los.

Ich habe den Link zum Django-Projekt gefunden sehr nützlich, wollte aber nicht jedes Mal, wenn ich einen Ajax-Aufruf tätigen wollte, den zusätzlichen JavaScript-Code einfügen müssen.

Ich mag Jerrykans Antwort, da sie sehr prägnant ist und einem ansonsten normalen Ajax-Anruf nur eine Zeile hinzufügt. Wie wäre es mit dem Laden des csrfmiddlewaretoken aus dem DOM als Antwort auf die Kommentare unter seinem Kommentar zu Situationen, in denen keine Django-Vorlagen-Tags verfügbar sind?

var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
jQuery.ajax({
    type: 'POST',
    url: url,
    data: { 'csrfmiddlewaretoken': token },
    dataType: 'json',
    success: function(data) { console.log('Yippee! ' + data); } 
});

EDIT März 2016

Mein Ansatz zu diesem Thema hat sich in den letzten Jahren geändert. Ich füge den folgenden Code (aus den Django-Dokumenten ) zu einer main.js-Datei hinzu und lade ihn auf jeder Seite. Sobald Sie fertig sind, sollten Sie sich keine Gedanken mehr über das CSRF-Token mit Ajax machen müssen.

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;
}
var csrftoken = getCookie('csrftoken');


4

Include - x-csrftokenHeader in Anfrage:

var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
jQuery.ajax({
    type: 'POST',
    url: url,
    beforeSend : function(jqXHR, settings) {
        jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie());
    },
    data: data,
    dataType: 'json',

});

3

Die schnellste Lösung ohne Plugins, wenn Sie js nicht in Ihre Vorlage einbetten, ist:

<script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>Fügen Sie vor Ihren Verweis auf die Datei script.js in Ihre Vorlage ein und fügen Sie sie csrfmiddlewaretokenIhrem dataWörterbuch hinzu:

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })

Wenn Sie Ihre js in die Vorlage einbetten, ist dies so einfach wie: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}


0

Wenn nach dem Lesen anderer Antworten immer noch Probleme auftreten, versuchen Sie Folgendes:

   $.ajax({
            type: "POST",
            beforeSend: function (request)
            {
                request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}");
            },
            url: servlet_path,
            data : data,
            success : function(result) {
            console.log("Success!");
   }
});

Ich konnte dies nicht wie hier beschrieben zum Laufen bringen. Irgendwelche Ideen? Es scheint, als beforeSendob die Eigenschaft den Token nicht richtig greift ...?
Twknab

Wenn sich noch jemand wundert, ist es X-CSRFTOKEN, nicht X-CSRF-TOKEN. Achten Sie auf die Bindestriche.
Endre Both

0

Bitte beachten Sie nicht, dass Sie auf diese Weise sicherstellen müssen, dass {% csrf_token %}die <form></form>Tags nicht enthalten sind . Fügen Sie dann, wie hier erläutert , den folgenden Code zu Ihrem Javascript hinzu

    function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // 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;
    }
    const csrftoken = getCookie('csrftoken');

// using js fetch
// https://docs.djangoproject.com/en/3.1/ref/csrf/#setting-the-token-on-the-ajax-request
    const request = new Request(
    /* URL */,
    {headers: {'X-CSRFToken': csrftoken}}
);
fetch(request, {
    method: 'POST',
    mode: 'same-origin'  // Do not send CSRF token to another domain.
}).then(function(response) {
    // ...
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.