|
const express = require('express'); |
|
const router = express.Router(); |
|
const session = require('express-session'); |
|
const MemcachedStore = require('connect-memcached')(session); |
|
const _ = require('lodash'); |
|
const utils = require('../../services/application/utils'); |
|
const config = utils.getConfiguration(); |
|
/** |
|
* Middleware which goes in before Express Session to enable overriding session ID assignment through a query parameter |
|
* or a request header `uid` |
|
* @param req - The Express Request Object |
|
* @param res - The Express Response Object |
|
* @param next |
|
*/ |
|
function overrideSessionAssignment(req, res, next) { |
|
/* Hack to fool express session middleware to think that we are using the legacy cookie-parse middleware |
|
* to enable session assignment through headers/query parameters for cookieless flows |
|
* |
|
* To retrieve the session ID, the Express Session middleware first checks req.headers.cookie and tries to |
|
* parse the session ID from there. If it doesn't find this value, it checks for it in req.signedCookies (that's |
|
* where cookie-parser usually puts signed cookies) for backward compatibility with the older method of using |
|
* cookie-parse middleware in conjunction with the express session middleware. |
|
* |
|
* This middleware simulates this by deleting the req.headers.cookie field and setting the value obtained |
|
* from the URL or headers into req.signedCookies[<cookie_name>]] |
|
* |
|
* [Interesting conversation on the Security Implications](https://github.com/expressjs/session/pull/159) |
|
* |
|
* References: |
|
* 1. Express Session Source Code where this check happens |
|
* [Express Session: index.js#L547](https://github.com/expressjs/session/blob/89fd7156129210f2b0c350afcbdf226665a8328c/index.js#L537) |
|
* |
|
* 2. Issues and PRs Regarding This topic on Express Session: |
|
* [Adds optional session getter Pull#40](https://github.com/expressjs/session/pull/40) |
|
* [Manually set sessionID Pull#159](https://github.com/expressjs/session/pull/159) |
|
* [Can't set manual ID Issue#158](https://github.com/expressjs/session/issues/158) |
|
* [Cookies disabled results in loss of session (no workaround via Header) Issue#185](https://github.com/expressjs/session/issues/185) |
|
* [Trouble upgrading to Express 4 + standalone session middleware... Issue#148](https://github.com/expressjs/session/issues/148) |
|
*/ |
|
if (req.query.uid || req.headers.sl_uid) { |
|
//Save the cookie header if any and delete the cookie header |
|
req.headers._sl_cookie = '' + req.headers.cookie; |
|
delete req.headers.cookie; |
|
|
|
//Add the expected key under signedCookies |
|
//This will trigger a deprecated warning in the logs from express session - we can ignore that. |
|
req.signedCookies = req.signedCookies || {}; |
|
req.signedCookies[config.application.session.middleware.name] = req.query.uid || req.headers.uid; |
|
} |
|
next(); |
|
} |
|
|
|
/** |
|
* Middleware to run after express session to let other middleware down the chain to treat this as a cookieless session |
|
* if the session was over written by the query or the headers. |
|
* @param req - The Express Request Object |
|
* @param res - The Express Response Object |
|
* @param next |
|
*/ |
|
function initializeNoCookieSession(req, res, next) { |
|
if (req.query.uid || req.headers.uid) { |
|
req.session.cookieless = true; |
|
req.session.nocookie = req.session.nocookie || {}; |
|
} |
|
next(); |
|
} |
|
|
|
//Override Session assignment if needed |
|
router.use(overrideSessionAssignment); |
|
|
|
//Express Session Setup |
|
let sessionConfig = _.merge({}, config.application.session.middleware); |
|
//Use Memcached if production or stage. else, use default memory store |
|
sessionConfig.store = (config.instance.env !== 'dev') ? new MemcachedStore(sessionConfig.store) : undefined; |
|
router.use(session(sessionConfig)); |
|
|
|
//Override as no cookies if session ID was overwritten using query or header |
|
router.use(initializeNoCookieSession); |
|
|
|
module.exports = router; |
|
|
|
/** |
|
* TODO: Investigate if there is any way to optimize TTL of no cookie session. |
|
* Perhaps make session treat it like a session cookie? |
|
* Sessions with no cookies will not be relevant after the window is closed but will still be occupying space in storage |
|
* Fixing these sessions with a short ttl or some such other strategy will see large performance gains at scale |
|
*/ |
|
|
|
/** |
|
* TODO: Fix session hijacking vulnerability. |
|
* Hack scenario: |
|
* 1. Attacker opens appplication and retrieves the session ID (either from in memory or from the URL |
|
* 2. Attacker shares URL with UID parameter as query to the Target |
|
* 3. Target opens URL using the uid which overrides the cookie flow |
|
* 4. Target logs in |
|
* 5. Attacker can now hijack the session as the session id remains the same. |
|
* |
|
* Possible Solutions: |
|
* 1. Always give the cookies, if present, priority to determine the session [simple] |
|
* 2. Refresh the session ID after authentication [R&D needed. How would one do that using Express Session] |
|
* |
|
* |
|
*/ |