I have a little probleme with my Nodejs application. I want protect my forms with csrf token, but it's not work. I have an error like
ForbiddenError: invalid csrf token
POST http://localhost:3000/addfile 403 (Forbidden)
I want to create csrf token for all requests. I can create csrf token, but if I use the methods like : POST/PUT or DELETE it's not work.
I don't understand why I have this error. Thanks for yours answers.
app.js
var express = require("express");
var bodyParser = require("body-parser");
var mongoose = require('mongoose');
var fs = require('fs');
var path = require('path');
var logger = require('morgan');
var expressValidator = require('express-validator');
var csrf = require('csurf');
var session = require('express-session');
var passport = require('passport');
var PORT = 3000;
var config = require('./config/database');
var app = express();
// Connexion to MongoDb
mongoose.connect(config.database, function(err) {
if(err){
console.log(err);
}
else{
console.log("Connected to MongoDb");
}
});
// Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(expressValidator());
app.set('views',path.join(__dirname, ''));
app.set('view engine','pug');
app.use(express.static(path.join(__dirname, '')));
app.disable('x-powered-by');
app.use(session({
name: 'SESS_ID',
secret: config.secret,
resave: true,
saveUninitialized: true,
cookie: {
secure: false,
httpOnly: true,
maxAge: 5*60*1000 } //15minutes*60sec*1000ms
//cookie: {secure: false} //https = true, http=false
}));
app.use(csrf());
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
app.use(function(req, res, next) {
res.locals._csrf = req.csrfToken();
next();
});
app.use('/', require('./routes/fileRoutes'));
app.use('/', require('./routes/authRoutes'));
app.listen(PORT,function(){
console.log("Server started at the port " + PORT);
});
routes/fileRoutes.js
app.get('/',function(req,res){
File.find(function(err, files){
res.render('views/layout',{files:files});
});
});
app.post('/addfile',upload,function(req,res){
if (req.fileValidationError) {
return res.end("Error PDF");
} else {
for (var i = 0; i < req.files.length; i++)
{
var files = new File ();
files.fieldname= req.files[i].fieldname;
files.originalname= req.files[i].originalname;
files.encoding= req.files[i].encodin;
files.path= req.files[i].path;
files.save(function(err, data){
});
}
res.redirect('/');
}
});
layout.pug
form#uploadForm(enctype='multipart/form-data', action='/addfile', method='post')
input(type='hidden', name='_csrf', value=_csrf)
input(type='file', name='userPhoto', multiple='')
input(type='submit', value='Upload Image', name='submit')
input#random(type='text', name='random')
I see you have:
input(type='hidden', name='_csrf', value=_csrf)
What is the value for if you console.log(_csrf)? I also noticed you didn't put that one in quotes.
Related
Im trying to implement infinite scroll. In my first route I load 5 elements from the data base and store the id of the last seen item. To load more data getNextHomeContent is called, but for some reason req.session.lastseen is undefined.
server.js
var express = require('express');
var session = require('express-session');
var app = express();
var mongoose = require('mongoose');
var logger = require('morgan');
var bodyParser = require('body-parser');
var cors = require('cors');
//imports database configuration
var databaseConfig = require('./config/database');
//defines route file to use
var router = require('./app/routes');
//connect to datbase
mongoose.connect(databaseConfig.url);
app.listen(process.env.PORT || 8080);
console.log("App listening on port 8080");
app.use(bodyParser.urlencoded({ extended: false })); // Parses urlencoded bodies
app.use(bodyParser.json()); // Send JSON responses
app.use(logger('dev')); // Log requests to API using morgan
app.use(cors());
app.use(session({
resave: true,
saveUninitialized: true,
secret: 'keyboard cat',
cookie: {
maxAge: 60000,
secure: false
}
}));
router(app);
And here is my controller for my routes in homeCtrl.js
exports.getHomeContent = function(req, res, next) {
req.session.lastseen = null;
homeContent.find({})
.sort({
"_id": -1
})
.limit(5)
.exec(function(err, content) {
if (err) {
res.send(err);
}
var last = content.slice(-1);
req.session.lastseen = last[0]._id;
console.log("lastseen first is " + req.session.lastseen);
res.json(content);
});
}
exports.getNextHomeContent = function(req, res, next) {
console.log("lastseen is " + req.session.lastseen);
homeContent.find({
"_id": { "$lt": req.session.lastseen }
})
.sort({
"_id": -1
})
.limit(5)
.exec(function(err, content) {
if (err) { res.send(err); }
console.log("WTF:" + content.slice(-1));
var lastitem = content.slice(-1);
req.session.lastseen = lastitem[0]._id;
res.json(content);
});
}
When get Home content runs, req.session.lastname is set to the ID of the last item. However req.session.lastitem becomes undefined when getNextHomeContent() runs. Can anyone help me with this?
Thanks!!
Trying to get sessions set up with Redis. I have my Redis DB in a dokku container, linked to my app (also in a dokku container). I keep getting a session undefined.I've stripped things back to the bare minimum, also checked the order in which things are run. I still get an undefined.
I've read here 'session' is undefined when using express / redis for session store and Express js session undefined to no avail.
I shouldn't need to use cookie-parser, as expression-session has cookie stuff in it, and the docs say cookie-parser can cause problems with expression-session.
var express = require('express');
var session = require('express-session');
var redisStore = require('connect-redis')(session);
var bodyParser = require('body-parser');
var app = express();
app.set('port', (process.env.PORT || 5000));
var redisURL = 'redis://xxxxx:1234567#bar-redis-foo:6379';
var store = new redisStore({ url: redisURL });
app.use(session({
secret: 'ssshhhhh',
store: store,
saveUninitialized: true,
resave: true
}));
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json()); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.get('/', function(req, res, next) {
console.log(req.session); // Logs Undefined
res.send('Hello');
});
Check your redis connection and run again. Sample code is following line.
"use strict";
const express = require("express");
const bodyParser = require("body-parser");
const session = require("express-session");
const RedisStore = require("connect-redis")(session);
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(session({
secret: "$kx(Fj$uB!Ug!#jCkguFmc6f7t<c-e$9",
resave: false,
saveUninitialized: true,
store: new RedisStore({
url: "redis://:********#pub-redis-12766.eu-central-1-1.1.ec2.redislabs.com:12766",
ttl: 5 * 60 // 5 minute (Session store time)
})
}));
app.use(function (request, response, next) {
let path = request.originalUrl;
if (request.session.user) {
request.session.reload(function (err) { //session expire time regenerate
if (!err) {
next();
} else {
response.redirect('/login');
}
});
} else {
if (path == '/login') {
next();
} else {
response.redirect('/login');
}
}
});
app.get('/', function(request, response) {
if (request.session.user) {
response.send(request.session.user);
} else {
response.redirect("/login");
}
});
app.get('/login', function(request, response) {
if (request.session.user) {
response.redirect("/");
} else {
request.session.user = {username: "halil"}; //custom key {user} and custom data {username: "halil"}
}
response.send('Login');
});
app.get('/logout', function(request, response) {
if (request.session.user) {
request.session.destroy();
response.redirect("/login");
} else {
response.redirect("/login");
}
});
app.listen(app.get('port'), function () {
console.log('App is working on port: ' + app.get('port'));
});
I could send messages before, but I shared passport's sessions with express and socket.io using redis by following this tutorial http://www.scotthasbrouck.com/blog/2016/3/18/passportjs-express-session-with-sockeio and now I can no longer send any chat messages.
Also, in my routes req.isAuthenticated() always returns false but I didn't have this problem before.
This is my server.js.
// server.js
// set up ======================================================================
// get all the tools we need
var express = require('express');
var app = express();
var server = require('http').Server(app);
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var configDB = require('./config/database.js');
var http = require('http').Server(app);
var io = require('socket.io')(http);
var passportSocketIo = require('passport.socketio');
var session = require('express-session');
var chatdb = require('./app/models/chat.js');
var user = require('./app/models/user.js');
var redis = require('redis');
var client = redis.createClient();
var RedisStore = require('connect-redis')(session);
// configuration ===============================================================
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
app.set('view engine', 'ejs'); // set up ejs for templating
var sessionStore = new RedisStore({ host: 'localhost', port: 6379, client: client, ttl: 260 });
// required for passport
app.use(session({
secret: 'secret',
store: sessionStore,
resave: true,
saveUninitialized: true,
cookie: {
secure: process.env.ENVIRONMENT !== 'development' && process.env.ENVIRONMENT !== 'test',
maxAge: 2419200000
},
}));
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.use(express.static(__dirname + '/views'));
app.use(express.static(__dirname + '/public'));
io.use(passportSocketIo.authorize({
key: 'connect.sid',
secret: 'secret',
store: sessionStore,
passport: passport,
cookieParser: cookieParser,
}));
var eventSocket = io.of('/chat');
// socket.io
io.on('connection', function (socket) {
console.log('a user connected');
socket.on('chat message', function(msg){
var name = "efe";
chatdb.saveMsg({name: name, msg: msg}, function(err){
if(err) throw err;
io.emit('chat message', msg);
});
if (socket.request.user && socket.request.user.logged_in) {
console.log(socket.request.user);
}
});
});
// routes ======================================================================
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
// launch ======================================================================
http.listen(port);
console.log('The magic happens on port ' + port);
I had the same problem. I tried to implement passport.socketio like you but I solved my problem without it.
Here is my middleware :
// Express session middleware
var sessionMiddleware = session({ secret: 'secret-key', resave: true, saveUninitialized: true });
// Send Express sessionMiddleware through socket.io
io.use(function(socket, next){
// Params: request object, response object and callback.
sessionMiddleware(socket.request, {}, next);
});
The second parameter (response object) of sessionMiddleware function is empty. This will renders the session read-only.
And Here is how I use passport js session variable to get user informations :
io.on("connection", function(socket){
socket.on('chat message', function(msg){
var passport = socket.request.session.passport; // Get the passport variable
// Check if passport session exists
if (passport && typeof passport !== 'undefined'){
var userSession = passport.user; // Get the user session
// Build JSON with user session data
var message = {
message : msg,
name : userSession.name,
avatar : userSession.avatar
};
io.emit('chat message', message); // Emit my socket
}
});
});
Hope it help.
This was how i was able to solve it.
var express = require('express');
var app = express();
var server = require('http').Server(app);
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
// Add connect-mongo to project - npm install connect-mongo
var MongoStore = require('connect-mongo')(session);
var configDB = require('./config/database.js');
var http = require('http').Server(app);
var io = require('socket.io')(http);
var chatdb = require('./app/models/chat.js');
// configuration ===============================================================
// NOTE: This might need to be put into a callback/promise inside an initialize function
var db = mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
app.set('view engine', 'ejs'); // set up ejs for templating
var mongoStore = new MongoStore({
mongooseConnection: db.connection,
});
app.use(session({
secret: 'secret',
clear_interval: 900,
cookie: { maxAge: 2 * 60 * 60 * 1000 },
store: mongoStore,
}));
// required for passport
app.use(session({ secret: 'secret' })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.use(express.static(__dirname + '/views'));
app.use(express.static(__dirname + '/public'));
// Intercept Socket.io's handshake request
io.use(function(socket, next) {
// Use the 'cookie-parser' module to parse the request cookies
cookieParser('secret')(socket.request, {}, function(err) {
// Get the session id from the request cookies
var sessionId = socket.request.signedCookies ? socket.request.signedCookies['connect.sid'] : undefined;
if (!sessionId) return next(new Error('sessionId was not found in socket.request'), false);
// Use the mongoStorage instance to get the Express session information
mongoStore.get(sessionId, function(err, session) {
if (err) return next(err, false);
if (!session) return next(new Error('session was not found for ' + sessionId), false);
// Set the Socket.io session information
socket.request.session = session;
// Use Passport to populate the user details
passport.initialize()(socket.request, {}, function() {
passport.session()(socket.request, {}, function() {
// This will prohibit non-authenticated users from connecting to your
// SocketIO server.
if (socket.request.user) {
next(null, true);
} else {
next(new Error('User is not authenticated'), false);
}
});
});
});
});
});
// socket.io
io.on('connection', function(socket) {
socket.on('chat message', function(msg) {
console.log(socket.request.user.facebook.name || socket.request.user.local.email);
var name = socket.request.user.facebook.name || socket.request.user.local.email;
chatdb.saveMsg({
name: name,
msg: msg
}, function(err) {
if (err) throw err;
io.emit('chat message', msg);
});
});
socket.on('disconnect', function() {
console.log('user disconnected');
});
});
// routes ======================================================================
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
// launch ======================================================================
http.listen(port);
console.log('The magic happens on port ' + port);
I'm trying to get express-session to store the session in Redis, but it doesn't seem like it wants to save. When I revert back to default session store it works flawlessly. The Redis daemon is hosted on a Vagrant VM with default configuration, and the app is able to connect to it, although it doesn't want to save sessions to it.
Here's my code:
var express = require('express');
var glob = require('glob');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var compress = require('compression');
var methodOverride = require('method-override');
var session = require('express-session');
var passport = require('passport');
var redis = require('redis');
var RedisStore = require('connect-redis')(session);
var auth = require('./passport');
var flash = require('connect-flash');
module.exports = function(app, config) {
app.set('views', config.root + '/app/views');
app.set('view engine', 'jade');
// app.use(favicon(config.root + '/public/img/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(session({
store: new RedisStore({
host: config.redis.host,
port: config.redis.port
}),
secret: config.secret,
saveUninitialized: true,
resave: false
}));
/*app.use(session({
secret: config.secret,
saveUninitialized: true,
resave: true
}));*/
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(compress());
app.use(express.static(config.root + '/public'));
app.use(methodOverride());
var controllers = glob.sync(config.root + '/app/controllers/*.js');
controllers.forEach(function (controller) {
require(controller)(app);
});
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
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,
title: 'error'
});
});
}
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {},
title: 'error'
});
});
};
As you can see, I got the default one commented out, and if I remove those comments and comment out the redis store, it works as it should. Any clues why this is happening? I'm not getting a single error.
You probably have some connection errors, but connect-redis does not output them to console (see connect-redis source code). To see them you can create a separate module that creates a client instance and pass it to RedisStore constructor:
// redisClient.js
var redis = require('redis');
var redisClient = redis.createClient('localhost', 6379); // replace with your config
redisClient.on('error', function(err) {
console.log('Redis error: ' + err);
});
module.exports = redisClient;
Redis client emits also other event that may be helpful in debugging - see node-redis docs
// your code
var redisClient = require('./redisClient.js`);
(...)
app.use(session({
store: new RedisStore({
client: redisClient
}),
secret: config.secret,
saveUninitialized: true,
resave: false
}));
I'm using express and socket.io and I want to share the express session between the two, with each one being on a different Node instance (localhost:3000 and localhost:8000). So far, express will create the session and the cookie created, however socket.io only picks up the 'io' cookie, not the express cookie. Can anyone show mw here my error is? I'm using express 4.x and socket.io 1.x.
Express config (localhost:3000):
var cookieParser = require('cookie-parser')
, session = require('express-session')
, bodyParser = require('body-parser')
, express = require('express')
, redis = require('redis')
, RedisStore = require('connect-redis')(session);
module.exports = function (app, passport) {
app.use(express.static('./static'))
app.use(cookieParser("thisismynewsecret"));
app.use(session({
//passport: passport,
name: 'sid',
//key: 'express.sid',
secret: 'thisismynewsecret',
saveUinitialized: true,
resave: true,
store: new RedisStore({ client: redis.createClient() }),
cookie: {
httpOnly: true,
path: '/',
secure: false
}
}));
app.use(passport.initialize());
app.use(passport.session());
// all environments
app.set('port', process.env.PORT || 3000)
app.set('views', './views')
app.set('view engine', 'jade')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(require('method-override')());
app.use( require('express-subdomain-handler')({ baseUrl: 'localhost', prefix: 'myprefix', logger: true }) );
}
});
socket.io (localhost:8000):
var fs = require('fs');
var session = require('express-session');
var cookie = require('cookie');
var cookieParser = require('cookie-parser');
var sessionStore = require('connect-redis')(session);
var server = require('http').Server(function(req, res) {
fs.readFile(__dirname + '/views/JAMinit.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
}).listen(8000);
var io = require('socket.io')(server);
io.use(function(socket, next) {
var data = socket.handshake || socket.request;
if (data.headers.cookie) {
data.cookie = cookie.parse(cookieParser.signedCookie(data.headers.cookie, 'thisismynewsecret'));
console.log(data.cookie);
console.log('data.cookies ( %s )', JSON.stringify(data.cookie));
if (data.cookie.sid) {
data.sid = data.headers.cookie.sid;
sessionStore.get(data.headers.cookie.sid, function(err, session) {
data.session = session;
});
}
}
next();
});
Check out express.io, it combines express and socket.io and has automatic session support.