it-swarm.com.de

jQuery fügt den Daten aller $ .post () -Anfragen ein CSRF-Token hinzu

Ich arbeite an einer Laravel 5-App, bei der der CSRF-Schutz standardmäßig für alle POST -Anforderungen aktiviert ist. Ich mag diese zusätzliche Sicherheit, deshalb versuche ich damit zu arbeiten.

Während ich eine einfache $.post()-Anfrage machte, erhielt ich einen 'Illuminate\Session\TokenMismatchException'-Fehler, da die erforderliche Formulareingabe _token in den POST -Daten fehlte. Hier ist ein Beispiel für eine $ .post-Anfrage:

var userID = $("#userID").val();
$.post('/admin/users/delete-user', {id:userID}, function() {
// User deleted
});

Ich habe mein CSRF-Token als Meta-Feld in meinem Header gespeichert und kann leicht darauf zugreifen:

var csrf_token = $('meta[name="csrf-token"]').attr('content');

Ist es möglich, dies bei allen ausgehenden $.post()-Anforderungen an die Json-Daten anzuhängen? Ich habe versucht, Header zu verwenden, aber Laravel schien sie nicht zu erkennen - 

var csrf_token = $('meta[name="csrf-token"]').attr('content');
alert(csrf_token);
$.ajaxPrefilter(function(options, originalOptions, jqXHR){
    if (options['type'].toLowerCase() === "post") {
        jqXHR.setRequestHeader('X-CSRFToken', csrf_token);
    }
});
21
NightMICU

Ihr $.ajaxPrefilter-Ansatz ist gut. Sie müssen jedoch keine Kopfzeile hinzufügen. Sie müssen lediglich eine Eigenschaft zur data-Zeichenfolge hinzufügen.

Daten werden als zweites Argument für $.post bereitgestellt und dann als Abfragezeichenfolge (id=foo&bar=baz&...) formatiert, bevor der Vorfilter auf die Option data zugreifen kann. Daher müssen Sie der Abfragezeichenfolge ein eigenes Feld hinzufügen:

var csrf_token = $('meta[name="csrf-token"]').attr('content');
$.ajaxPrefilter(function(options, originalOptions, jqXHR){
    if (options.type.toLowerCase() === "post") {
        // initialize `data` to empty string if it does not exist
        options.data = options.data || "";

        // add leading ampersand if `data` is non-empty
        options.data += options.data?"&":"";

        // add _token entry
        options.data += "_token=" + encodeURIComponent(csrf_token);
    }
});

Dadurch wird aus id=userIDid=userID&_token=csrf_token.

24
apsillers

Aus der Laravel-Dokumentation:

Sie können das Token beispielsweise in einem "Meta" -Tag speichern:

Nachdem Sie das Meta-Tag erstellt haben, können Sie eine Bibliothek wie .__ anweisen. jQuery, um das Token zu allen Anforderungsheadern hinzuzufügen. Dies ermöglicht eine einfache praktischer CSRF-Schutz für Ihre AJAX - basierten Anwendungen:

$ .ajaxSetup ({ Headers: { 'X-CSRF-TOKEN': $ ('meta [name = "csrf-token"]'). attr ('content') }} ;

So können Sie zum Beispiel eine Anfrage machen.

Fügen Sie dieses Meta-Tag Ihrer Ansicht hinzu: 

<meta name="csrf-token" content="{{ csrf_token() }}">

Und dies ist ein Beispielskript, mit dem Sie mit Laravel kommunizieren können (sendet eine Anfrage, wenn Sie auf ein Element mit id = "some-id" klicken und die Antwort in einem Element mit id = "result" angezeigt wird):

<script type="text/javascript">
    $(document).ready(function(){

        $.ajaxSetup({
            headers:
            { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }
        });

        $("#some-id").on("click", function () {
            var request;


            request = $.ajax({
                url: "/your/url",
                method: "POST",
                data:
                {
                    a: 'something',
                    b: 'something else',
                },
                datatype: "json"
            });

            request.done(function(msg) {
                $("#result").html(msg);
            });

            request.fail(function(jqXHR, textStatus) {
                $("#result").html("Request failed: " + textStatus);
            });
        });

    });
</script>
17
Kornel

Im Allgemeinen stimme ich dem von Kornel vorgeschlagenen Konzept zu, mit einer Ausnahme. 

Ja, Laravel empfiehlt, $.ajaxSetup zu verwenden. Dies wird jedoch nicht empfohlen, da diese Methode alle nachfolgenden Ajax-Anforderungen beeinflusst. Es ist richtiger, die Ajax-Einstellungen für jede Anforderung festzulegen. Sie können zwar Sachen neu einstellen:

Alle nachfolgenden Ajax-Aufrufe, die eine Funktion verwenden, verwenden die neuen Einstellungen, sofern sie nicht von den einzelnen Aufrufen überschrieben werden, bis zum nächsten Aufruf von $ .ajaxSetup ().

Wenn Sie $.ajax() verwenden, ist es günstiger, entweder die data-Eigenschaft oder headers zu verwenden. Laravel erlaubt CSRF-Token sowohl als Anforderungsparameter als auch als Header.

Zuerst fügen Sie der Ansicht das folgende Meta-Tag hinzu

<meta name="csrf-token" content="{{ csrf_token() }}">

Und dann eine Ajax-Anfrage machen:

$.ajax({
    url: "/your/url",
    method: "POST",
    data:
    {
        a: 'something',
        b: 'something else',
        _token: $('meta[name="csrf-token"]').attr('content')
    },
    datatype: "json"
});

OR

$.ajax({
    url: "/your/url",
    method: "POST",
    data:
    {
        a: 'something',
        b: 'something else',
    },
    headers: 
    {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
    datatype: "json"
});
6
Alex Baklanov

Die Django-Dokumentation zu CSRF enthält ein Nice-Code-Snippet mit ajaxSetup zum automatischen Hinzufügen des entsprechenden Headers zu allen Anforderungstypen, auf die es ankommt:

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", csrftoken);
        }
    }
});
5
phk

es gibt eine viel einfachere Methode, dies zu tun, indem Sie die Daten wie vor dem Senden serialisieren

<form method="post" id="formData">
 <input type="text" name="name" >
 <input type="hidden" name="_token" value="{{ csrf_token() }}">
 <input type="submit" id="sub" class="btn btn-default" value="Submit" />                            
</form>
<script>
    $(document).on('submit', '#formData', function (event) {
    event.preventDefault();
     var formData = $('#formData').serialize();
    $.ajax({
        url: url,
       type: "POST",
       data : formData,   
                success: function (result) {
                    console.log(result);                             
                }
           });
        });

    });
</script>

alles mit einem Namensattr wird in eine Abfrage gestellt und übergeben 

0
c319113

Ich denke, dass die oben genannte Lösung möglicherweise nicht so gut funktioniert. Wenn Sie das tun:

var x; 
x + ""
// "undefined" + empty string coerces value to string 

Sie erhalten Daten wie "undefined_token = xxx"

Wenn Sie beispielsweise die obige Lösung für das Löschen von Laravel verwenden, müssen Sie Folgendes überprüfen:

if (typeof options.data === "undefined")
    options.data = "";
else
    options.data += "&";
options.data = "_token=" + csrf_token;
0