Session state with Express

Session state is a technique for storing application data for a user's browsing session. Data can be stored in a cookie, in-memory on the web server, or remotely in a database or state server. This article will discuss storage of session data in Node.js using Express 3.

Cookie Session Storage

This technique stores data in cookies on the user's browser. Session data is transmitted with each request between the browser and the server. By default this cookie is an HttpOnly cookie to help prevent tampering. Cookie Storage has the following pros and cons:

PRO: Session data is retained when the web server is restarted
PRO: Allows for load balancing between multiple web servers
CON: Higher request overhead since all session data is transmitted with each request
CON: Session data is limited to 4KB (hard limit of cookie storage)
CON: Sensitive data cannot be stored since data is transmitted in plain text

var express = require('express')  
  , app = express();

app.use(express.cookieParser());  
app.use(express.cookieSession({ secret: 'derp derp' }));

// Shows the session data and cookie settings
app.get('/', function(req,res) {  
  res.send(req.session);
});

// Sets a key to a value, removes a key if no value is set
app.get('/set', function(req, res) {  
  var key = req.query.key;
  var value = req.query.value;
  req.session[key] = value;
  res.send(req.session);
});

// Clears the session data by setting the value to null
app.get('/clear', function(req, res) {  
  req.session = null;
  res.send(req.session);
});

console.log('Listening on 8000');  
app.listen(8000);  

To enable cookie session storage you will need to enable the cookieSession. The cookieParser middleware will parse cookie data and store it in the cookies property on the request object, req.cookies. The cookieSession middleware is used to store parse this cookie and store session data in req.session

Tampering

Disabling HttpOnly mode, you can view access the session data in the browser, which is a bad but I wanted to check what would happen if you tamper with the data.

app.use(express.cookieSession({ secret: 'derp derp', cookie: { httpOnly: false } }));  

This data, by default is stored in a cookie called connect.sess (the name of the cookie can be configured). The cookie includes a hash of the data to prevent tampering. Note that the data is NOT encrypted so it is transmitted in plaintext over the wire with each request and can be intercepted.

connect.sess=s:j:{"derp":"turkey","brian":"mancini"}.oId7hf/ZswTlz8Zg1+biscoyJFKhooymO+JxPj+B+Xs  

If the value of the data is tampered with, it will completely reset session data.

Size Limit Exceeded

What happens if you exceed the limit? The value will not be set. From what I could gather the max data size you can set is 3024 bytes of data before it won't store the session data.

In-Memory Session Storage

This type of storage is the default storage mechanism for many frameworks. Data is stored in the web server's memory and is accessed via a session identifier. The session identifier is stored as an encrypted cookie that gets transmitted with each request. In-Memory storage has the following pros and cons:

PRO: Sensitive data can be stored since data is stored on the web server
PRO: Session data size limits are much higher than cookie storage and are based on amount of memory in the web server
PRO: Minimal request overhead since only the session identifier is transmitted
CON: Session data is reset when the web server is restarted
CON: Does not allow for load balancing between multiple web servers since data

var express = require('express')  
  , app = express();

app.use(express.cookieParser());  
app.use(express.session({ secret: 'derp derp' }));

// Shows the session data and cookie settings
app.get('/', function(req, res) {  
  res.send(req.session);
});

// Sets a key to a value, removes a key if no value is set
app.get('/set', function(req, res) {  
  var key = req.query.key;
  var value = req.query.value;
  req.session[key] = value;
  res.send(req.session);
});

// Clears the session data by setting the value to null
app.get('/clear', function(req, res) {  
  req.session = null;
  res.send(req.session);
});

console.log('Listening on 8000');  
app.listen(8000);  

To enable in-memory session storage you will need to use the session implemented in Connect. The session middleware will add session data to req.session and allow modification and retrieval.

External Stores

The most complex solution, but arguably best solution is to use an external store such as MySql, MongoDB, or Redis for storage.

PRO: Session data is retained when the web server is restarted
PRO: Allows for load balancing between multiple web servers
PRO: Low Higher request overhead since all session data is transmitted with each request
PRO: Sensitive data can be stored since data is stored on the web server
PRO: Session data size limits are much higher than cookie storage and are based on amount of memory in the data store
PRO: Minimal request overhead since only the session identifier is transmitted
CON: Requires external system for data storage

You can implement your own Session Store mechanism by following the "Session Store Implementation" section of the Connect Session API. Once implemented, you can plug it in by setting the storage property when configuring session:

function MyStore() {  
   this.get(sid, cb) {
      // gets data
   }
   this.set(sid, val, cb) {
      // sets data
   }
   this.destroy(sid, cb) {
      // destroys session data
   }
}
app.use(express.session({  
    secret: 'derp derp',
    store: new MyStore()
  }));

Examples for Redis and Mongo can be found here:

https://github.com/visionmedia/connect-redis
https://github.com/kcbanner/connect-mongo

comments powered by Disqus