Node.js csrf()403将nodejs从0.10升级到10.15.1时禁止出现错误
在我们的mean(mysql express angularjs和node)应用程序中,我们已经将node js版本从0.10.16升级到了10.15.1。 csrf()令牌验证问题令人担忧 在 帕格先生Node.js csrf()403将nodejs从0.10升级到10.15.1时禁止出现错误,node.js,angularjs,express,pug,csrf,Node.js,Angularjs,Express,Pug,Csrf,在我们的mean(mysql express angularjs和node)应用程序中,我们已经将node js版本从0.10.16升级到了10.15.1。 csrf()令牌验证问题令人担忧 在 帕格先生 .content form.login-form(action='/auth/signin', method='post', accept-charset='utf-8', novalidate='') input(type='
.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);
/**
*模块依赖关系。
*/
var express=require('express.io'),
闪存=需要(“连接闪存”),
config=require('./config'),
acl=require('connect-roles'),
csrf=express.csrf(),
sanitizer=require('sanitize-html'),
crypto=require('crypto'),
_=需要('下划线'),
winston=require('./winston'),
摩根=要求(“摩根”);
module.exports=函数(应用程序、护照、rest、数据库){
应用程序集('showStackError',true);
//应放在express.static之前
app.use(express.compress({
过滤器:功能(req、res){
返回(/json | text | javascript | css/).test(res.getHeader('Content-Type'));
},
级别:9
}));
//设置fav图标和静态文件夹
app.use(express.favicon());
//app.use(express.static(config.root+/public));
app.use('/assets',express.static(config.root+'/public/assets');
使用('/js',express.static(config.root+'/public/js'));
使用('/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');
//不要将记录器用于测试环境
if(process.env.NODE_env!=“test”){
app.use(express.logger('dev'));
}
app.use(morgan('combined',{stream:winston.stream}));
//设置视图路径、模板引擎和默认布局
app.set('views',config.root+'/app/views');
应用程序集(“查看引擎”、“翡翠”);
//启用jsonp
app.enable('jsonp回调');
app.configure(函数(){
应用程序使用(函数noCachePlease(请求、恢复、下一步){
res.header('Cache-Control','no-store');
res.header('Content-Security-Policy','frame-祖先'自我');
res.header('X-Frame-Options','DENY');
next();
});
//cookieParser应该在会话之上
app.use(express.cookieParser('mc_secret');
//bodyParser应该在methodOverride之上
使用(express.json());
app.use(express.urlencoded());
//消毒
应用程序使用(功能(请求、恢复、下一步){
如果(请求正文){
_.每个(请求主体、功能(值、键){
如果(!parseInt(值,10)&&value!==null){
如果(值的类型=='string'){
value=value.replace(//gi,'>');
value=value.replace(//gi,'