node.js - 将 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(/</gi, '<');
value = value.replace(/(©|"|&)/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() 并删除它,因为它显示无效令牌并且没有修复它。
解决方案
推荐阅读
- authentication - OWASP ZAP -(身份验证)从响应中提取令牌并将其用于下一个请求
- ruby - 创建一个异步方法,该方法在指定的时间后抛出异常,除非在该函数之外满足某个条件
- c# - 将包含名称的文件从源复制到目标c#
- powershell - 如何使用 PowerShell 在文件中查找特定文本?
- json - aws s3 sync / aws s3 cp 下载的 json 文件不完整
- rdf - RDF/OWL 本体中 URI 的批量更改
- prometheus - 如何计算普罗米修斯仪表定义的曲线下面积
- java - Android 房间迁移测试失败,但没有任何改变
- jenkins - 在声明性詹金斯的阶段内并行运行
- sql - 如何创建将在没有 sqlplus lib 的 CentOS 上运行 SQL 文件的 sh 脚本