To comply with GDPR without an annoying cookie banner, I would like the public pages on my website to not store cookies. To facilitate the journey of registered users, I would like to use flash messages. The problem is that these two seem incompatible, as setting sessions:
const session = require('express-session');
// Initialize mongodb session storage to remember users.
const store = new MongoDBStore({
uri: config.mongoUri,
// The 'expires' option specifies how long after the last time this session was used should the session be deleted.
// Effectively this logs out inactive users without really notifying the user. The next time they attempt to
// perform an authenticated action they will get an error. This is currently set to 3 months (in milliseconds).
expires: max_session_ms,
});
// Enable sessions using encrypted cookies
app.use(
session({
cookie: {
// Specifies how long the user's browser should keep their cookie, probably should match session expiration.
maxAge: max_session_ms,
sameSite: "strict",
},
store: store,
secret: config.secret,
signed: true,
resave: false, // Unknown effect. See https://github.com/expressjs/session#resave
saveUninitialized: false, // Save only explicitly, e.g. when logging in.
httpOnly: true, // Don't let browser javascript access cookies.
secure: config.secureCookies, // Only use cookies over https in production.
})
);
and flash messages with:
const flash = require("express-flash"); // Disabled to avoid cookies.
app.use(flash());
stores a cookie in the browser with an empty flash message for public pages. I don't think server-side only flash messages exist (see Server-side only flash messages (no cookies) ). I tried setting res.locals but it gets erased between redirects.
Is it possible to store cookies only for visitors who agreed to the terms in the logged-in area of the website and not for visitors in general?
3 remarks about your question :
requesting consent is not based on GDPR, it's requested by EU directive 2002/58/CE
this directive states explicitly that you don't need to request consent if you are storing a session on user's browser
storing a cookie or a flash is the same from EU directive's point of view, you can't avoid requesting consent in the case it's required by replacing cookies by anything that writes data in user's browser
if the rules are not clear for you, check the CNIL's page (French data authority protection) for example : https://www.cnil.fr/fr/nouvelles-regles-cookies-et-autres-traceurs-bilan-accompagnement-cnil-actions-a-venir
EDIT :
For everyone, to clarify when consent is needed, it's best you read the text of the directive directly it's very clear (article 5.3 directive ePrivacy 2002/58) :
Member States shall ensure that the use of electronic communications networks to store information or to gain access to
information stored in the terminal equipment of a subscriber or user
is only allowed on condition that the subscriber or user concerned is
provided with clear and comprehensive information (...) about the purposes of the processing,
and is offered the right to refuse such processing by the data
controller. This shall not prevent any technical storage or access for
the sole purpose of carrying out or facilitating the transmission of a
communication over an electronic communications network, or as
strictly necessary in order to provide an information society service
explicitly requested by the subscriber or user.
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'm quite new to OAuth and not sure what to do with the access token I receive from another party. Right now I'm using express session on https with secure and httpOnly settings. This works fine, until I upload an image on the same API server (which happens after I add a product). Everytime my server detects changes, the token I saved becomes undefined, this means that the user has to go through the whole OAuth process again.
Since I use MYSQL, is it possible to save the token information in the database (expiry, refreshtoken, accesstoken) linked to the user or is there a better way to save this data?
My setup is very basic, I have one API Server and one React app for front-end.
I receive the token information by making an API call with my own API to the other party, the response from this party is what I end up sending as cookies to the React app.
This is the session code I have right now:
app.use(
session({
secret: process.env.SESSION_SECRET,
name: "token",
cookie: {
secure: true,
httpOnly: true,
},
resave: true,
saveUninitialized: true,
})
);
For anyone that runs into the same problem, by default express session uses MemoryStore. I missed this when I was reading the documentation.
MemoryStore is purposely not designed for a production environment. It
will leak memory under most conditions, does not scale past a single
process, and is meant for debugging and developing.
To fix this, you can use either "cookie-session" or pick one of the stores from the documentation.
https://www.npmjs.com/package/express-session#compatible-session-stores
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 followed a tutorial to include Google authentication for my web application using the passport-google-oauth module. The server.js file has the following lines of code:
app.use(express.session({ secret: 'victoriassecret' })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
In addition, I find that the application automatically logs the user out after some time. Passport is configured in a separate file that is imported in server.js. Is there some way I can increase the time before the user is logged out, or even better, not log him out until he clicks on the logout button? Also, what is the session secret?
1) You can define the maximum life-time of a session cookie ( and concurrently the time before a user is automatically logged out ) using the maxAge option of the cookie parameter like this :
app.use(expressSession({ cookie: {maxAge: 10000} , secret: 'victoriassecret'}));
According to this maxAge value ( 10000 ) the cookie's maximum life-time will be 10.000ms(10 sec).
(obviously you need a much bigger value than this)
Thus,you can increase the maxAge value in order to suit your needs and make sure user does not get logged out until he decides so, pressing the Logout button.
2) The session secret is a random string used to hash the session with HMAC ( more on HMAC : here) in order to protect the session from being highjacked.
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).