Skip to content

Commit 42630cb

Browse files
authored
Merge pull request #900 from jaredhanson/fix-fixation
Address Session Fixation Concerns
2 parents 5e6d92f + 8dd79fe commit 42630cb

File tree

4 files changed

+724
-27
lines changed

4 files changed

+724
-27
lines changed

lib/http/request.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ req.logIn = function(user, options, done) {
3636
if (typeof done != 'function') { throw new Error('req#login requires a callback function'); }
3737

3838
var self = this;
39-
this._sessionManager.logIn(this, user, function(err) {
39+
this._sessionManager.logIn(this, user, options, function(err) {
4040
if (err) { self[property] = null; return done(err); }
4141
done();
4242
});
@@ -51,12 +51,22 @@ req.logIn = function(user, options, done) {
5151
* @api public
5252
*/
5353
req.logout =
54-
req.logOut = function() {
54+
req.logOut = function(options, done) {
55+
if (typeof options == 'function') {
56+
done = options;
57+
options = {};
58+
}
59+
options = options || {};
60+
5561
var property = this._userProperty || 'user';
5662

5763
this[property] = null;
5864
if (this._sessionManager) {
59-
this._sessionManager.logOut(this);
65+
if (typeof done != 'function') { throw new Error('req#logout requires a callback function'); }
66+
67+
this._sessionManager.logOut(this, options, done);
68+
} else {
69+
done && done();
6070
}
6171
};
6272

lib/sessionmanager.js

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
var merge = require('utils-merge');
2+
13
function SessionManager(options, serializeUser) {
24
if (typeof options == 'function') {
35
serializeUser = options;
@@ -9,30 +11,85 @@ function SessionManager(options, serializeUser) {
911
this._serializeUser = serializeUser;
1012
}
1113

12-
SessionManager.prototype.logIn = function(req, user, cb) {
14+
SessionManager.prototype.logIn = function(req, user, options, cb) {
15+
if (typeof options == 'function') {
16+
cb = options;
17+
options = {};
18+
}
19+
options = options || {};
20+
21+
if (!req.session) { return cb(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
22+
1323
var self = this;
14-
this._serializeUser(user, req, function(err, obj) {
24+
var prevSession = req.session;
25+
26+
// regenerate the session, which is good practice to help
27+
// guard against forms of session fixation
28+
req.session.regenerate(function(err) {
1529
if (err) {
1630
return cb(err);
1731
}
18-
// TODO: Error if session isn't available here.
19-
if (!req.session) {
20-
req.session = {};
21-
}
22-
if (!req.session[self._key]) {
23-
req.session[self._key] = {};
24-
}
25-
req.session[self._key].user = obj;
26-
cb();
32+
33+
self._serializeUser(user, req, function(err, obj) {
34+
if (err) {
35+
return cb(err);
36+
}
37+
if (options.keepSessionInfo) {
38+
merge(req.session, prevSession);
39+
}
40+
if (!req.session[self._key]) {
41+
req.session[self._key] = {};
42+
}
43+
// store user information in session, typically a user id
44+
req.session[self._key].user = obj;
45+
// save the session before redirection to ensure page
46+
// load does not happen before session is saved
47+
req.session.save(function(err) {
48+
if (err) {
49+
return cb(err);
50+
}
51+
cb();
52+
});
53+
});
2754
});
2855
}
2956

30-
SessionManager.prototype.logOut = function(req, cb) {
31-
if (req.session && req.session[this._key]) {
57+
SessionManager.prototype.logOut = function(req, options, cb) {
58+
if (typeof options == 'function') {
59+
cb = options;
60+
options = {};
61+
}
62+
options = options || {};
63+
64+
if (!req.session) { return cb(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
65+
66+
var self = this;
67+
68+
// clear the user from the session object and save.
69+
// this will ensure that re-using the old session id
70+
// does not have a logged in user
71+
if (req.session[this._key]) {
3272
delete req.session[this._key].user;
3373
}
74+
var prevSession = req.session;
3475

35-
cb && cb();
76+
req.session.save(function(err) {
77+
if (err) {
78+
return cb(err)
79+
}
80+
81+
// regenerate the session, which is good practice to help
82+
// guard against forms of session fixation
83+
req.session.regenerate(function(err) {
84+
if (err) {
85+
return cb(err);
86+
}
87+
if (options.keepSessionInfo) {
88+
merge(req.session, prevSession);
89+
}
90+
cb();
91+
});
92+
});
3693
}
3794

3895

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
"main": "./lib",
3737
"dependencies": {
3838
"passport-strategy": "1.x.x",
39-
"pause": "0.0.1"
39+
"pause": "0.0.1",
40+
"utils-merge": "^1.0.1"
4041
},
4142
"devDependencies": {
4243
"make-node": "0.3.x",

0 commit comments

Comments
 (0)