2019-10-18 08:59:00 -04:00
|
|
|
const Metrics = require('metrics-sharelatex')
|
|
|
|
const logger = require('logger-sharelatex')
|
|
|
|
|
|
|
|
function computeValidationToken(req) {
|
|
|
|
// this should be a deterministic function of the client-side sessionID,
|
|
|
|
// prepended with a version number in case we want to change it later
|
|
|
|
return 'v1:' + req.sessionID.slice(-4)
|
|
|
|
}
|
|
|
|
|
2019-10-22 03:29:19 -04:00
|
|
|
function checkValidationToken(req) {
|
|
|
|
if (req.session) {
|
|
|
|
const sessionToken = req.session.validationToken
|
|
|
|
if (sessionToken) {
|
|
|
|
const clientToken = computeValidationToken(req)
|
|
|
|
// Reject invalid sessions. If you change the method for computing the
|
|
|
|
// token (above) then you need to either check or ignore previous
|
|
|
|
// versions of the token.
|
|
|
|
if (sessionToken === clientToken) {
|
|
|
|
Metrics.inc('security.session', 1, { status: 'ok' })
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
logger.error(
|
|
|
|
{
|
|
|
|
sessionToken: sessionToken,
|
|
|
|
clientToken: clientToken
|
|
|
|
},
|
|
|
|
'session token validation failed'
|
|
|
|
)
|
|
|
|
Metrics.inc('security.session', 1, { status: 'error' })
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Metrics.inc('security.session', 1, { status: 'missing' })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true // fallback to allowing session
|
|
|
|
}
|
|
|
|
|
2019-10-18 08:59:00 -04:00
|
|
|
module.exports = {
|
|
|
|
enableValidationToken(sessionStore) {
|
|
|
|
// generate an identifier from the sessionID for every new session
|
|
|
|
const originalGenerate = sessionStore.generate
|
|
|
|
sessionStore.generate = function(req) {
|
|
|
|
originalGenerate(req)
|
|
|
|
// add the validation token as a property that cannot be overwritten
|
|
|
|
Object.defineProperty(req.session, 'validationToken', {
|
|
|
|
value: computeValidationToken(req),
|
|
|
|
enumerable: true,
|
|
|
|
writable: false
|
|
|
|
})
|
|
|
|
Metrics.inc('security.session', 1, { status: 'new' })
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-10-22 03:29:19 -04:00
|
|
|
validationMiddleware(req, res, next) {
|
|
|
|
if (!checkValidationToken(req)) {
|
|
|
|
// the session must exist for it to fail validation
|
|
|
|
req.session.destroy(() => {
|
|
|
|
return next(new Error('invalid session'))
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
return next()
|
2019-10-18 08:59:00 -04:00
|
|
|
}
|
2019-10-22 05:08:49 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
hasValidationToken(req) {
|
|
|
|
if (req && req.session && req.session.validationToken) {
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
2019-10-18 08:59:00 -04:00
|
|
|
}
|
|
|
|
}
|