Express.js csrf 令牌 jQuery Ajax

Express.js csrf token with jQuery Ajax

我正在尝试在我的项目中实施 csrf 保护,但我无法使其与 jQuery Ajax 一起使用。 (虽然它适用于普通的帖子请求)

如果我在发送表单之前使用 chrome 开发工具篡改令牌,我仍然会看到 "data is being processed" 文本而不是 invalid csrf token 错误。

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var bodyParser = require('body-parser');
var router = express.Router();
var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
//app.set('strict routing', true);
app.set('view options', {layout: false});

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());

var csrfProtection = csrf({ cookie: true });
var parseForm = bodyParser.urlencoded({ extended: false });

app.use(express.static(path.join(__dirname, 'public')));

app.get('/form', csrfProtection, function(req, res) {
    // pass the csrfToken to the view
    res.render('send', { csrfToken: req.csrfToken() });
});


app.post('/form', parseForm, csrfProtection, function(req, res) {
    res.send('data is being processed');
});


// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function (err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;

send.jade

html
    head
        meta(name='_csrf', content='#{csrfToken}')
    body
        form(action='/form', method='POST')
            |   Favorite color:
            input(type='text', class="favori", name='favoriteColor')
            button(type='submit') Submit
    script(src="javascripts/frontend/jquery/jquery-3.0.0-alpha1.js")
    script(src="javascripts/test.js")

test.js

$(document).ready(function () {

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

    $('button').click(function (e) {
        e.preventDefault();
        var text = $('.favori').val();
        alert(text);
        $.post(
            "/form",
            {
                text: text
            }, function (data) {
                console.log(data);
            });
    });
});

检查 header 以查看它是否在 cookie 中或作为表单数据的一部分传递了被篡改的标记。看起来您的设置是为了使用 cookie。所以在表单上更改它不应该影响 cookie。让我知道这是否有助于揭示问题。

在负载消息中发送 CSRF 令牌:

$('button').click(function (e) {
    e.preventDefault();
    var text = $('.favori').val();
    alert(text);
    $.post(
        "/form",
        {
            text: text,
            _csrf : $('meta[name="_csrf"]').attr('content')
        }, function (data) {
            console.log(data);
        });
});

为了方便您的工作,我认为您可以创建一个 Jquery 插件来完成它,如下所示:

(function( $ ) {
    $.postCSRF = function(to, message, callback) {
        message._csrf = $('meta[name="_csrf"]').attr('content');
        $.post(to, message, callback);
    };
}( jQuery ));

// Usage example:
$.postCSRF('/form',{text:'hi'},function(res) {
    console.log(res);
});

示例:http://jsfiddle.net/w7h4Lkxn/

您做的一切都完全正确,但您必须完全禁用对 cookie 的检查!

var csrfProtection = csurf({ cookie: false });

作者在这里提到了 https://github.com/expressjs/csurf/issues/52

感谢上面的 header post 代码,因为这对于验证 express session 令牌至关重要,我已经与其他人分享了它