首页 > 解决方案 > 将 nodejs 从 0.10 升级到 10.15.1 时出现 csrf() 403 禁止错误

问题描述

在我们的平均(mysql express angularjs 和 node)应用程序中,我们已将 node js 版本从 0.10.16 升级到 10.15.1。csrf() 令牌验证问题正在引发关注。

http://hostname/auth/sign signin.pug

   .content
             form.login-form(action='/auth/signin', method='post', accept-charset='utf-8', novalidate='')
                 input(type='hidden', name='_csrf', value=token)
                 login form goes below

express.js

/**
 * Module dependencies.
 */
var express = require('express.io'),
    flash = require('connect-flash'),
    config = require('./config'),
    acl = require('connect-roles'),
    csrf = express.csrf(),
    sanitizer = require('sanitize-html'),
    crypto = require('crypto'),
    _ = require('underscore'),
    winston = require('./winston'),
    morgan = require('morgan');

module.exports = function (app, passport, rest, db) {
    app.set('showStackError', true);

    //Should be placed before express.static
    app.use(express.compress({
        filter: function (req, res) {
            return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
        },
        level: 9
    }));

    //Setting the fav icon and static folder
    app.use(express.favicon());
   // app.use(express.static(config.root + '/public'));
    app.use('/assets', express.static(config.root + '/public/assets'));
    app.use('/js', express.static(config.root + '/public/js'));
    app.use('/minjs', express.static(config.root + '/public/minjs'));
    app.use('/resources', express.static(config.root + '/public/resources'));
    //  app.use('/views',express.static(config.root + '/public/views'));

    //Don't use logger for test env
    if (process.env.NODE_ENV !== 'test') {
        app.use(express.logger('dev'));
    }
    app.use(morgan('combined', { stream: winston.stream }));

    //Set views path, template engine and default layout
    app.set('views', config.root + '/app/views');
    app.set('view engine', 'jade');

    //Enable jsonp
    app.enable('jsonp callback');

    app.configure(function () {

        app.use(function noCachePlease(req, res, next) {
            res.header('Cache-Control', 'no-store');
            res.header('Content-Security-Policy', "frame-ancestors 'self'");
            res.header('X-Frame-Options', 'DENY');
            next();
        });

        //cookieParser should be above session
        app.use(express.cookieParser('mc_secret'));

        //bodyParser should be above methodOverride
        app.use(express.json());
        app.use(express.urlencoded());

        //sanitize
        app.use(function (req, res, next) {
            if (req.body) {
                _.each(req.body, function (value, key) {
                    if (!parseInt(value, 10) && value !== null) {
                        if (typeof value === 'string') {
                            value = value.replace(/>/gi, '>');
                            value = value.replace(/&lt;/gi, '<');
                            value = value.replace(/(&copy;|&quot;|&amp;)/gi, '');
                            req.body[key] = sanitizer(value, {
                                allowedTags: []
                            });
                        }
                    }
                });
            }
            return next();
        });

        app.use(express.methodOverride());

        var session = require('express-session');
        var SessionStore = require('express-mysql-session')(session);

        var options = {
            host: config.db.local.options.host,
            port: config.db.local.options.port,
            user: config.db.local.username,
            password: config.db.local.password,
            database: config.db.local.name
        };

        var sessionStore = new SessionStore(options);

        var sessionOptions = {
            key: 'mc_cookies',
            secret: 'mc_secret',
            store: sessionStore,
            resave: false,
            saveUninitialized: false
        };


        //production HTTPS
        //AWS Issue: Can't set a secure cookie on ELB
        // It might be because the traffic hitting your instances is not SSL
        // It is decrypted by then
        if (process.env.MC_ENV === 'local') {
            app.enable('trust proxy');
            sessionOptions.proxy = true;
            sessionOptions.cookie = {
                httpOnly: true,
                secure: true
            };

            /*
            app.use(function (req, res, next) {
                if (!req.secure) {
                    return res.redirect('https://' + req.host + req.url);
                }
                next();
            });
            */
        }

        app.use(function (req, res, next) {
            next();
        });
        app.use(session(sessionOptions));

        //  app.use(express.session(sessionOptions));

        /* Allow only app to post/get requests */
        var conditionalCSRF = function (req, res, next) {
            //('conditionalCSRF: ', req.method, req.url);

            //OAuth2 URLs
            var whitelist = [
                '/oauth2/authorize/decision',
                '/oauth2/token',
                '/oauth2/signin',

            ];

            if (process.env.MC_ENV === 'local') {
                req.csrfNeeded = true;
                if (whitelist.indexOf(req.url) !== -1 && req.method === 'POST') {
                    req.csrfNeeded = false;
                    next();
                } else {
                    console.log('csrf(): ', req.method, req.url);
                    csrf(req, res, next);
                }
            }
            else
                next();
        };

        app.use(conditionalCSRF);

        //since the csrf does not block GET requests let's ban them manually
        function createToken(salt, secret) {
            return salt + crypto
                .createHash('sha1')
                .update(salt + secret)
                .digest('base64');
        }
        function checkToken(token, secret) {
            if ('string' !== typeof token) return false;
            return token === createToken(token.slice(0, 10), secret);
        }

        app.use(function (req, res, next) {
            var isAllowed = true;
            //console.log('req.csrfNeeded: ', req.csrfNeeded);

            if (req.csrfNeeded) {
                res.cookie('XSRF-TOKEN', req.csrfToken());
                res.locals.token = req.csrfToken();

                if ((req.method === 'POST' || req.method === 'GET') &&
                     req.url.indexOf('/api/v2/') !== -1) {
                    var secret = req.session._csrfSecret;
                    var val = req.headers['x-xsrf-token'];
                    isAllowed = checkToken(val, secret);
                }
                next();
            }

            //console.log('csrfNeeded check: ', req.method, req.url, isAllowed);

            if (!isAllowed) {
                res.status(403);
                res.render('403.pug', {error: '403: Forbidden'});
            } else {
                next();
            }
        });

        //connect flash for flash messages
        app.use(flash());
        //use passport session
        app.use(passport.initialize());
        app.use(passport.session());
        app.use(require('../app/lib/middleware/rest')(rest));
        app.use(require('../app/lib/middleware/db')(db));

        //routes should be at the last
        app.use(app.router);

        //Acl section
        app.use(acl);

需要为应用程序启用 csrf(),我尝试通过添加新包 csruf() 并删除它,因为它显示无效令牌并且没有修复它。

标签: node.jsangularjsexpresspugcsrf

解决方案


推荐阅读