简体   繁体   English

forbiddenError / 403 Ajax Express Csurf-如何正确使用Csurf?

[英]forbiddenError/403 Ajax Express Csurf - how to use Csurf correctly?

Hey Guys so I've been at this for a week and I can't quite figure it out. 嗨,大家好,我已经待了一个星期了,我不太清楚。

I'm building a phaser game and I set up a scoreboard using node, it's my first time using node and I can't quite figure out how to use csurf as the documentation is so confusing. 我正在构建一个移相器游戏,并使用node设置了记分板,这是我第一次使用node,并且由于文档太混乱,我无法弄清楚如何使用csurf。

 ForbiddenError: invalid csrf token
    at verifytoken (/Users/jorybraun/web/highscore/node_modules/csurf/index.js:269:11)
    at csrf (/Users/jorybraun/web/highscore/node_modules/csurf/index.js:97:7)
    at Layer.handle [as handle_request] (/Users/jorybraun/web/highscore/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/Users/jorybraun/web/highscore/node_modules/express/lib/router/index.js:312:13)
    at /Users/jorybraun/web/highscore/node_modules/express/lib/router/index.js:280:7
    at Function.process_params (/Users/jorybraun/web/highscore/node_modules/express/lib/router/index.js:330:12)
    at next (/Users/jorybraun/web/highscore/node_modules/express/lib/router/index.js:271:10)
    at /Users/jorybraun/web/highscore/app.js:43:5
    at Layer.handle [as handle_request] (/Users/jorybraun/web/highscore/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/Users/jorybraun/web/highscore/node_modules/express/lib/router/index.js:312:13)

I'm getting a 403 error every time i try to send an jquery post request to my route score route from the index route. 每次我尝试从索引路由向我的路由得分路由发送jquery post请求时,都会收到403错误。 I really like to limit the access to the routes so that you can't actually visit them unless you're making an internal ajax request. 我真的很想限制对路由的访问,以使您无法真正访问它们,除非您发出内部ajax请求。

So here is my app.js file 这是我的app.js文件

// app.js
var mongodb      = require('mongodb');
var monk         = require('monk');
var credentials  = require('./credentials');
var db           = monk(credentials.uri);
var express      = require('express');
var path         = require('path');
var favicon      = require('serve-favicon');
var logger       = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser   = require('body-parser');
var csrf        = require('csurf');
var loadCsrf    = csrf({ cookie: true })
var parseForm   = bodyParser.urlencoded({ extended: false })


var scores       = require("./routes/scores");
var routes       = require('./routes/index'); 

var app          = express();

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

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


app.use(loadCsrf);

app.use('/', routes);
app.use('/scores', scores);

index route index.js 索引路由index.js

    var express = require('express');
var router = express.Router();

    /* GET home page. */
    router.get('/', function(req, res, next) {
      res.render('index', { csrfToken: req.csrfToken() })
    });

score route scores.js 得分路线scores.js

// scores.js 

var express = require('express');
var router = express.Router();


// GET scores, sorted by time
router.get('/', function(req, res) {
  console.log('GET scores');
  // Get the database object we attached to the request
  var db = req.db;
  // Get the collection
  var collection = db.get('scores');
  // Find all entries, sort by time (ascending)
  collection.find({}, { sort: { score : 1 } }, function (err, docs) {
    if (err) {
        // Handle error
        console.error('Failed to get scores', err);
        res.status(500).send('Failed to get scores');
    } else {
        // Respond with the JSON object
        res.json(docs);
    }
  });
});

// GET a number of top scores
// (the /top route without a number won't work unless we add it)
router.get("/top/:number", function(req, res) {
    console.log("GET top scores");
    // Read the request parameter
    var num = req.params.number;
    var db = req.db;
    var collection = db.get("scores");
    // Get all scores, but limit the number of results
    collection.find({}, { limit: num, sort: { score : 1 } }, function(err, docs) {
        if (err) {
            console.error("Failed to get scores", err);
            res.status(500).send("Failed to get scores");
        } else {
            res.json(docs);
        }
    });
});

// POST a score
router.post("/", function(req, res) {
    module.exports = router
    console.log("POST score");
    var name = req.body.name;
    var score = Number(req.body.score);
    var email = req.body.email;
    if (!(name && score)) {
        console.error("Data formatting error");
        res.status(400).send("Data formatting error");
        return;
    }
    var db = req.db;
    var collection = db.get("scores");    
    collection.insert({
        "name": name,
        "score": score,
        "email": email

    }, function(err, doc) {
        if (err) {
            console.error("DB write failed", err);
            res.status(500).send("DB write failed");
        } else {
            // Return the added score
            res.json(doc);
        }
    }); 
});


module.exports = router;

Ajax request in the Phaser canvas, function submit() { Phaser画布中的Ajax请求,函数commit(){

    var name = prompt("Please enter your name");
    var email = prompt("Please enter your email adress, this will not be featured on the scoreboard");
    var csrf_token = "#{csrfToken}";

    $("body").bind("ajaxSend", function(elm, xhr, s){
      if (s.type == "POST") {
        xhr.setRequestHeader('X-CSRF-Token', csrf_token);
      }
    });


    $.post({
        url: 'http://localhost:3000/scores/',
        data: {

            name: name,
            email: email,
            score: score

        },
        success: function(data) {
            console.log('Score posted', data);
        },
        error: function(xhr, msg) {
            console.error('AJAX error', xhr.status, msg);
        }
    });

}

This resuts in an error like this: 这会导致如下错误:

n.ajaxTransport.l.cors.a.crossDomain.send   @   jquery.min.js:4
n.extend.ajax   @   jquery.min.js:4
n.each.n.(anonymous function)   @   jquery.min.js:4
submit  @   game.js:263
c.SignalBinding.execute @   phaser.min.js:8
c.Signal.dispatch   @   phaser.min.js:8
c.Button.onInputUpHandler   @   phaser.min.js:12
c.SignalBinding.execute @   phaser.min.js:8
c.Signal.dispatch

I've tried alot of different options but if some one can help me find a simple solution that would be amazing! 我尝试了很多不同的选择,但是如果有人可以帮助我找到一个简单的解决方案,那就太好了!

Thank you 谢谢

Ok so I figured out why this isn't working - I've gone through tons of stackoverflows and tutorials and everyone said to set it in the header. 好的,所以我弄清楚了为什么它不起作用-我经历了无数的stackoverflows和教程,每个人都说要在标题中设置它。 I haven't tested this but i think you need to use a different csrf token for the head to work. 我尚未对此进行测试,但我认为您需要使用其他csrf令牌才能正常工作。 This token is set in the body: 该令牌设置在主体中:

res.render('index', { csrfToken: req.csrfToken() })

And it's looking for a key pair value with _csrf as the key in the body. 它正在寻找以_csrf为主体的键对值。 This is currently working: 目前正在工作:

    var csrf_Token = getCsrfToken();  
    function getCsrfToken() { 
      var metas = document.getElementsByTagName('meta'); 

        for (i=0; i<metas.length; i++) { 
          if (metas[i].getAttribute("name") == "_csrf") { 
             return metas[i].getAttribute("content"); 
          } 
        } 

        return "";
      } 


    $.post({
        url: 'http://localhost:3000/scores/',
        data: {

            _csrf: csrf_Token,
            name: name,
            email: email,
            score: score

        },
        success: function() {
            console.log('Score posted');
        },
        error: function(xhr, msg) {
            console.error('AJAX error', xhr.status, msg);
        }
    });

If anyone can help me find another way to make this work I would love it as passing the token to the client through a meta tag doesn't really seem like the best way to do this. 如果有人可以帮助我找到另一种方法来完成这项工作,我会很喜欢它,因为通过meta标签将令牌传递给客户端并不是真正的最佳方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM