I've tried many ways of setting the session variables but have been unsuccessful in finding a solution. The problem more precisely is that the session (custome) variables are not being passed to other routes (so they aren't being stored in the default MemoryStore presumably).
All of the code is available at https://github.com/codexa/pictroid/blob/session/app.js
This is the portion of code for assigning the session variable (https://github.com/codexa/pictroid/blob/session/app.js#L304-311)
console.log(req.session);
req.session.regenerate(function(){
// Store the user's primary key
// in the session store to be retrieved,
// or in this case the entire user object
req.session.user = "some user";
req.session.auth = true;
});
I'm aware of the fact that this is async and the proceeding code will be executed while this does but making it synchronous doesn't solve the problem.
As an example, I'm trying to retrieve the custom "req.session.user" in the root dir route (https://github.com/codexa/pictroid/blob/session/app.js#L87-L88)
app.get('/', function(req, res) {
console.log(req.session.auth);
...
So can anyone please tell me what I'm doing wrong and how to solve it?
Thanks in advance.
You should not set secure: true if you are using http because cookies with secure: true will only be sent for https requests. If you want to keep secure: true, you will need to start an https server instead. If you are doing this only for development purposes, then you can just temporarily remove secure: true until you put your code into production (where you use https).
Also on an unrelated note, you can avoid regenerate() and the session fixation problem by only starting a session after a successful authentication and for authenticated routes. This will also help decrease the number of sessions in your session store from visitors who never sign in or crawlers (unless of course you need to store session data for unauthenticated users).
Related
Sorry guys, I'm really new to sessions and cookies and I'm trying to understand the mechanism behind it. I wanted to add register/login to my simple website and in order to do I need to understand web authentication and I really think I will have tons of questions regarding this topic.
Initially, I have register page that sends info after clicking submit button to a node server using express.
I'm trying to see what happens, so I've created a session in post route, it's created in the browser (connect.sid), then I commented out the part that creates that session and just tries to redisplay the session object, but it's undefined, but I still can see the session in the browser's cookies section, so what's going on? Thanks
app.use(session({
secret:"my test secret",
cookie:{},
resave:false,
saveUninitialized:false
}))
app.post("/register", (req, res) => {
req.session.usertest = "testsession_hardcodedvaluefornow";
console.log(req.session.usertest); // -> this is okay when above line to create is uncommented
//but when I comment the session assignment, it becomes undefined?
res.send("In register...");
})
I can see the session cookie even after commenting out the create session and posting over and over.
connect.sid s%3A_TahsTv0xhY-iHIdjDRblYJ_aZZ5oiSd.do7JcOGR1FaXPcFFIQ6hg5AW%2B0XVsYwIRO8vndyjDzs
req.session.id produces a different value (not undefined) even if I delete my session in the browser, so not sure where that comes from.
There is no "usertest" key in the session object, therefore it is undefined. The reason it's not undefined when you uncomment that line is because you create that key yourself in that instant with that line.
You can get the whole session object by using req.session, the session id by using req.session.id and the session cookie by using req.session.cookie.
Edit
To further clarify: a session will be made for every connected client. That is why you can see the cookie in the browser. That has no meaning however, it's just a way to uniquely identify that client (without actually telling you who that client is). Any information about that session (whether they're logged in, user id,...) needs to be stored in a session store. Express-session will use memory store by default, if the server restarts all that information will be lost, which is why that key doesn't exist. In order to preserve that information it has to be stored in a persistent session store. More information on session store implementations for express-session and how to use them can be found here: https://www.npmjs.com/package/express-session
As for the cookie values you get, those are the default ones set by express-session since you haven't set any yourself. You can change the maxAge to let it expire (or set it so 10 years or more for a more persistent session), you can specify a domain to which that cookie belongs, you can set it to secure (to only allow it over secure connections, e.g. https) and httpOpnly is by default true. httpOnly cookies cannot be accessed/altered by the client (although you can see them in the browser), do not set this to false.
I have some domain( maybe change very frequently), and two stable domain(e.g. auth.aaa.com, api.aaa.com).
Since express-session(https://www.npmjs.com/package/express-session) default get sessionid from cookie, but when crossing domain,ajax won't send cookie( I don't want to use something like Access-Control-Allow-Credentials ).
I want to add the sessionid to the querystring, and forge a cookie before express-session middleware.
app.use(function(req,res,next){
var ss = req.query.ss;
if(ss){
var signature = require('cookie-signature');
var cookie = require('cookie');
var signed = 's:' + signature.sign(ss, "secret");
var data = cookie.serialize('jsessionids', signed);
req.headers.cookie = data;
}
next();
})
app.use(session({
name:'jsessionids',
store: new redisStore({
host:config.redis.host,
port:config.redis.port,
pass : config.redis.password,
db: config.redis.database
}),
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'secret'
}));
is it reasonable? or any suggestion else?
It is generally not advisable to add the session as a query parameter, you have to jump through lots of hoops to get them to near the same level of security as cookies.
The main problem is that it is much more vulnerable to session fixation or session hijacking, which is where an attacker can steal and use another user's session.
Some key points to take into consideration
Query parameters are stored in browser history, bookmarks and referrer headers (just to name a few) which
could allow an attacker to use another users session on a shared
environment. Query string based sessions are much easier to leak outside their intended scope.
Cookies have better security mechanisms built in such as the
httpOnly flag which makes the cookies in-accessible to JavaScript
(whereas query strings are always accessible). The secure flag makes
sure that cookies are only sent over a secure connection (You could
perhaps use HSTS to help guard against MITM attacks for query string).
A user who share a link with their sessionID in the query string
which would allow any other user to assume their identity.
If you do decide to use the sessionID in the query string make sure you set an expiration time for the session and always to use TLS to securely transmit the session (same applies to any authentiction method).
Saying that, If you can avoid using query string based sessions, I would advise you do.
I cannot seem to figure a way to prevent Express/Connect to create sessions until I have a valid log in from the user.
The problem especially arises when using a DB-Backed Session Storage and calling the REST Services from non-browsers as in such cases, the Connect Session Object will create a new Session for each request which I do of course want to prevent.
However, I do need sessions whenever the user is authenticated as I am using Passport.js for authentication which requires sessions as well as I do require it to load session data from sent cookie information.
Looking at the source of the Connect Session Code, it seems it is always creating a new Session if none got sent from client without any option to prevent it..?
thanks
Alex
If you can easily identify calls to your API at query time you could do something like this:
app.use(function(req, res, next){
if ( req.path.indexOf("/api") == 0 ) return next();
else return express.session()( req, res, next );
});
This way the session middleware is only included if the request URL doesn't match some condition. I haven't tried this in anger though, so you might want to consider initialising express.session() outside the function, and make sure there aren't any other repercussions.
I have a requirement to create a session only after successful authentication.
I was able to create redisStore based session using express middleware, but it creates session when the first request comes to server.
But how I can create session only after successful authentication.
I googled somewhat, and foundreq.session.regenerate() (but I found the issue as below mentioned in this thread:
Regenerate session IDs with Nodejs Connect)
But in regenerate case also, it creates a fresh one, assuming old one is created already, and is created with same parameter.
So there is any other way to create a new session ID only after successful authentication..?
You may be conflating the idea of a session with the idea of an authenticated session.
It's normal for all users to have a session - even the anonymous, not-yet-logged-in users. The difference between this and an authenticated session is just that, locally on your web server, you specify that a particular user has been authenticated.
For example, once you authenticate someone, you can set:
req.session.isAuthenticated = true;
Then, when rendering pages, your controllers can do something like
function(req, res, next) {
if (!req.session.isAuthenticated) return res.redirect('/login');
res.render('appPage');
}
This might not be the exact answer you're looking for, but I'll answer the title for future readers:
From experimenting with my application, I've noticed that express-session sets the session cookie only if you manipulate the session object.
For example consider the below code:
app.post('/login', function (req, res) {
var authenticated = false;
if (req.session.authenticated) {
// session cookie is already set
authenticated = true;
} else if (/*validate the user here*/) {
console.log(' authenticating');
authenticated = true;
// if below line executes, the response will have Set-Cookie header
req.session.authenticated = authenticated;
}
res.json({
status: authenticated
//if --^ false, no session cookie will be set since we didn't manipulate session object
});
});
Even though a request creates a session object in memory for us to use, the Set-Cookie header seems to be sent only if we manipulate (or tamper with?) the session object created.
Unless we sent the Set-Cookie header along with the response and session id is stored in cookie at client side, I wouldn't consider it as an established session and worry about it.
Hope it helps.
Side note: This is the case of a cross-domain ajax request, might be different for normal http request, perhaps someone can confirm this
I need help understanding the concept of sessions for a web application. I am running a Node.js server with Express 3.0.
My goals are to:
Create a session for each user that logs in
Store this session and use it for validating if the user is already logged in (prevent two devices using the same user at the same time) and to limit access to certain pages (by matching session ID to some other data)
I will be using MemoryStore to save the sessions (seems easiest). If the above goals make sense can you provide a thorough explanation of how to achieve them?
Express has nice examples in the github repo. One of them deals with authentication and shows how to attach the user to the req.session object. This is done inside the app.post('/login') route.
To limit access to certain pages add a simple middleware to those routes
function restrict(req, res, next) {
if (req.session.user) {
next();
} else {
req.session.error = 'Access denied!';
res.redirect('/login');
}
}
app.get('/restricted', restrict, function(req, res){
res.send('Wahoo! restricted area, click to logout');
});
As Brandon already mentioned you shouldn't use the MemoryStore in production. Redis is a good alternative. Use connect-redis to access the db. An example config looks like this
var RedisStore = require('connect-redis')(express);
// add this to your app.configure
app.use(express.session({
secret: "kqsdjfmlksdhfhzirzeoibrzecrbzuzefcuercazeafxzeokwdfzeijfxcerig",
store: new RedisStore({ host: 'localhost', port: 3000, client: redis })
}));
Use MemoryStore in express ONLY if you are not creating multiple instances (such as with the cluster module). If you are load balancing across machines, your load balancer will need to use sticky / persistent sessions.
If you meet those requirements, then all you need to do is upon login, once the credentials are validated, set a session variable to indicate logged in, for example:
req.session.loggedIn = true;
If you want to check if a user is logged in, simply check that variable.
if (req.session.loggedIn) {
// user is logged in.
}
else {
// user is not logged in.
}
You mentioned preventing a single user from having sessions more than one session at a time. To achieve that, you may need to store something in a database indicating that the user is logged in. I warn you, this can be dangerous because of stale sessions. For example, what if a user logs in, but never logs out? What if they close their browser window so the session is gone forever?
Express has no concept of an idle session expiration. I have implemented such a thing by storing all sessions in the database along with a last accessed timestamp and then periodically clean up the session data based on the time. But then you need to update your list of who is logged in as well.