Javascript Node Express和csurf-403(禁止)无效的csrf令牌

Javascript Node Express和csurf-403(禁止)无效的csrf令牌,javascript,jquery,ajax,node.js,express,Javascript,Jquery,Ajax,Node.js,Express,通过谷歌搜索,我在这里和其他地方找到了所有我能找到的东西,但我就是无法通过。我正在使用Node、Express、EJS,并尝试在一个表单上使用csurf,该表单是通过jqueryajax发布的。无论我如何配置csurf,我都会得到“403(禁止)无效csrf令牌” 我尝试在app.js和控制器中全局配置。以下是我在app.js中尝试的内容: var express = require('express'); var session = require('express-session'); v

通过谷歌搜索,我在这里和其他地方找到了所有我能找到的东西,但我就是无法通过。我正在使用Node、Express、EJS,并尝试在一个表单上使用csurf,该表单是通过jqueryajax发布的。无论我如何配置csurf,我都会得到“403(禁止)无效csrf令牌”

我尝试在app.js和控制器中全局配置。以下是我在app.js中尝试的内容:

var express = require('express');
var session  = require('express-session');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mysql = require('mysql');
var flash = require("connect-flash");
var csrf = require("csurf");

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(session({
    secret: 'somethingsecret',
    resave: true,
    saveUninitialized: true,
    httpOnly: true,
    secure: false
}));
app.use(csrf());
app.use(function (req, res, next) {
    var token = req.csrfToken();
    res.cookie('XSRF-TOKEN', token);
    res.locals.csrfToken = token;
    console.log("csrf token = " + token);
    next();
});
app.use(flash());
app.use(express.static(path.join(__dirname, 'public')));

app.use(function (err, req, res, next) {
    if (err.code !== 'EBADCSRFTOKEN') return next(err);

    // handle CSRF token errors here
    res.status(403);
    res.send('form tampered with');
})

//routing
var routes = require('./routes/index');
var users = require('./routes/users');
var register = require('./routes/register');

app.use('/', routes);
app.use('/users', users);
app.use('/register', register);
…使用此控制器:

var express = require("express");
var router = express.Router();
var bodyParser = require("body-parser");
var userSvc = require("../service/userservice");

var jsonParser = bodyParser.json();

router.get("/", function(req, res, next) {
    console.log("token = " + token);
    userSvc.getAllPublicRoles(function(data) {
        res.render("register", {
            title: "Register a new account",
            roles: data
        });
    });
});

router.post("/new", jsonParser, function(req, res, next) {
    userSvc.addUser(req.body, function(result) {
        console.log("New user id = " + result.insertId);
        res.send('{"success" : "Updated Successfully", "status" : 200}');
    });
});
……这一观点:

表格:

然后我尝试在控制器中执行所有操作,从app.js中删除所有引用、调用等,并使用与上面相同的表单和ajax调用:

var express = require("express");
var router = express.Router();
var bodyParser = require("body-parser");
var csrf = require("csurf");
var userSvc = require("../service/userservice");

var csrfProtection = csrf();
var jsonParser = bodyParser.json();

router.get("/", csrfProtection, function(req, res, next) {
    var token = req.csrfToken();
    console.log("token = " + token);
    userSvc.getAllPublicRoles(function(data) {
        res.render("register", {
            title: "Register a new account",
            csrfToken: token,
            roles: data
        });
    });
});

router.post("/new", jsonParser, csrfProtection, function(req, res, next) {
    userSvc.addUser(req.body, function(result) {
        console.log("New user id = " + result.insertId);
        res.send('{"success" : "Updated Successfully", "status" : 200}');
    });
});

不知道从这里到哪里去。我在业余时间已经使用node大约两周了,请原谅我的无知。

如果您想将令牌存储在cookie中而不是会话中,请让csurf为您创建cookie,例如

// Store the token in a cookie called '_csrf'
app.use(csrf({cookie: true));

// Make the token available to all views
app.use(function (req, res, next){
    res.locals._csrf = req.csrfToken();
    next();
});
然后,您需要确保在使用AJAX通过POST数据或作为自定义请求头(如“xsrf令牌”)进行调用时,令牌可用

此时,您正在向表单提供令牌,而不是实际的请求(使用AJAX发送)

例如,您可以在AJAX设置中呈现令牌:

$.ajaxSetup({
   headers: {"X-CSRF-Token": "{{csrfToken}}" }
}); 

经过几个多小时的故障排除和搜索,我找到了一篇帮助解答这个问题的帖子。我所需要的只是在ajax帖子中传递标题值。有道理,我只是忽略了它。像这样:

<input type="hidden" id="_csrf" name="_csrf" value="<%= csrfToken %>" />
除了将“X-CSRF-Token”添加到post的标题之外,您还想完全禁用Cookie

var csrfProtection=csurf({cookie:false})

作者在这里提到了它

cookie和会话验证不应该结合在一起——尽管这有点误导,因为他在文档中结合了cookie和会话验证:

我个人项目的另一种方法是在我成功提交表单时重新发送一个新令牌:

例如,在我的表单(文件上传)上,我有以下html:

<form id="upload_form" type="multipart/form-data" data-csrf="{{csrfToken}}" method="post" action="/data_assets">
  <input id="excell_upload" type="file" style="visible:hidden" name="data_assets"/>
</form>
正如您所注意到的,我收到了一个新的csrf令牌,以便能够将我的表单重新用于新提交。我重新生成CSRF令牌,如下所示:

 $('#excell_upload').on('change',function(event){

      event.preventDefault();
      var formData = new FormData($("#upload_form")[0]);

      $.ajax({
        'type':$("#upload_form").attr('method'),
        'data': formData,
        'url': $("#upload_form").attr('action'),
        'processData': false,
        'contentType': false,
        'mimeType': 'multipart/form-data',
        'headers': {"X-CSRF-Token": $("#upload_form").attr('data-csrf') },
        'beforeSend': function (x) {
           if (x && x.overrideMimeType) {
               x.overrideMimeType("multipart/form-data");
          }
          $('#trigger_upload').addClass('disabled');
        },
        'success':function(data){
          $('#upload_form').attr('data-csrf',data.csrfToken)
        },
        'fail':function(){

        },
        'complete':function(){
          $('#trigger_upload').removeClass('disabled');
        }
      });
    });
app.post('/data_assets',function(req,res,next){
  res.json({'csrfToken':req.csrfToken()});
});

我试过了,然后根据我找到的其他样本把它去掉了。你说得对,我需要它来做饼干,但这并不是它最终起作用的原因。谢谢你的回答!这就是我的回答,当我说您需要在实际的AJAX请求中发送它时,我只是没有提供代码示例。我已经用其他人的一个样本更新了我的答案。@AshleyB-很公平,你应该为此得到赞扬。我曾经尝试过其他几种方法,直到我找到了一种有效的方法,所以一个例子对每个人都很有帮助。谢谢
<form id="upload_form" type="multipart/form-data" data-csrf="{{csrfToken}}" method="post" action="/data_assets">
  <input id="excell_upload" type="file" style="visible:hidden" name="data_assets"/>
</form>
 $('#excell_upload').on('change',function(event){

      event.preventDefault();
      var formData = new FormData($("#upload_form")[0]);

      $.ajax({
        'type':$("#upload_form").attr('method'),
        'data': formData,
        'url': $("#upload_form").attr('action'),
        'processData': false,
        'contentType': false,
        'mimeType': 'multipart/form-data',
        'headers': {"X-CSRF-Token": $("#upload_form").attr('data-csrf') },
        'beforeSend': function (x) {
           if (x && x.overrideMimeType) {
               x.overrideMimeType("multipart/form-data");
          }
          $('#trigger_upload').addClass('disabled');
        },
        'success':function(data){
          $('#upload_form').attr('data-csrf',data.csrfToken)
        },
        'fail':function(){

        },
        'complete':function(){
          $('#trigger_upload').removeClass('disabled');
        }
      });
    });
app.post('/data_assets',function(req,res,next){
  res.json({'csrfToken':req.csrfToken()});
});