csurf AJAX call - invalid CSRF token

家住魔仙堡 提交于 2019-12-11 01:55:49

问题


I'm using the express middleware csurf for CSRF protection. If I'm using it with forms, where I put the token into a hidden field, the action behind the routes works. Now I want to make a simple AJAX call but there csurf says its invalid.

AJAX call:

$('.remove').on('click', function () {
    var csrf = $(this).attr('data-csrf');
    $.ajax({
        type: 'DELETE',
        url: '/user/' + $(this).attr('data-id'),
        data: {
            _csrf: csrf
        },
        success: function (data) {
            //.....
        }
    });
});

And the part in the view:

<td class="uk-table-middle">
  <button data-id="{{ _id }}"  data-csrf="{{ csrfToken }}" class="uk-button-link uk-text-large remove">
      <i class="uk-icon-remove"></i>
  </button> 
</td>

And the init from the middleware:

import * as csurf from 'csurf';
// init bodyparse and and and...
app.use(csurf());

回答1:


I don't know in express but usually the CSRF token is inside a cookie, so you will need these two functions:

 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 csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

And then:

var csrftoken = getCookie('csrftoken');
$.ajax({
    url : formURL,
    type: "POST",
    data : postData,
    beforeSend: function(xhr, settings){
        if (!csrfSafeMethod(settings.type)) xhr.setRequestHeader("X-CSRFToken", csrftoken);
    },
    success:function(data, textStatus, jqXHR){

    },
    error: function(jqXHR, textStatus, errorThrown){
        //if fails
    }
});

Or if you don't want to use jQuery, you can use XMLHttpRequest to make the AJAX request:

var csrftoken = getCookie('csrftoken');
var xhr = new XMLHttpRequest();

xhr.open('POST', url);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader("X-CSRFToken", csrftoken);
xhr.onload = function(){
     if(xhr.status === 200){
         var response = JSON.parse(xhr.responseText);
         console.log(response)
     }
 };
 xhr.send(encodeURI('category=' + cat));



回答2:


The only reason why this method doesn't work is that you're not passing cookies with your ajax request. I was struggling when I figuring it out when I look into the code.

Csurf needs you to pass the secret key which stored on cookies (_csrf). Cookies have a limitation through the permission based on the domain (except your server allowing CORS)

On my case, I use fetch to passing the cookies with same domain request (i don't have to allow CORS)

const { _csrf, someData } = jsonData; // _csrf here you got from the form
const response = await fetch("/api/some/endpoint", {
  method: "POST",
  credentials: "same-origin", // here is the option to include cookies on this request
  headers: {
    "x-csrf-token": _csrf,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ someData })
});

Please note the code above I'm using es6 format. You may change same-origin with include if you requesting to different domain a.k.a CORS see the doc here

If you using jQuery as the library, this code could be useful to you. This code was untested and you should find out by yourself based on what library you use.

 $.ajax({
   url: 'http://your.domain.com/api/some/endpoint',
   xhrFields: { withCredentials: true }, // this include cookies
   headers: {'x-csrf-token': 'YourCSRFKey'}
 })

Please be free to use your own names on the headers, post data or querystring when passing the _csrf value. On my example above I'm using header with name x-csrf-token, but you can use other method based on screenshot code below.



来源:https://stackoverflow.com/questions/39264129/csurf-ajax-call-invalid-csrf-token

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!