Posted by David Bohannon on May 4, 2017
With MEAN stack applications, it is fairly common to store the session state client-side in either a JSON Web Token (JWT) or custom cookie object where the value is signed and/or encrypted. This eliminates the need to persist session data server-side and makes the application very scalable, especially among clustered servers. However, this convenience comes at a cost, specifically the inability to invalidate a user’s session. Setting the expiresIn or maxAge attribute on the session cookie only requests that the browser purge the cookie once it expires. However, if the cookie is replayed it will still be accepted by the server.
Session cookie purged from browser after 15 minutes
Session cookie is still accepted by the server after 15 minutes
The same issue applies when logging the user out of the application. The session cookie can be purged from the browser or set to null, but will still be valid if replayed.
This issue can be partially mitigated by maintaining an internal expiration value within the session cookie (assuming the cookie is signed to prevent tampering). The example application uses the client-sessions plugin which allows the developer to set an internal duration value that expires the cookie after a specified number of milliseconds. As shown in the code block and screenshot below, the internal session expiration is set to 30,000 milliseconds, or 5 minutes. Because the session can still not be invalidated manually, a shorter expiration value should be used than with conventional server-side session storage.
Client-sessions creation and duration time stamps used to invalidate the session server-side
The Csurf plugin is a very popular cross-site request forgery (CSRF) solution for Express applications with over 1.2 million downloads per month (as of March 2017). When this plugin is applied globally to all routes in Express via app.use(), it will be omitted from routes with methods listed in the ignoreMethods option which includes GET, HEAD, and OPTIONS methods by default. This means that if your application has any GET routes that modify state, they will not be protected from CSRF attacks. In the example MEAN Bug application, the GET route /secure/removeInvoice is not protected and is vulnerable to CSRF attack as shown below.
Invoice deleted by CSRF attack; GET request is not protected by Csurf middleware
However, the POST route /secure/addInvoice is protected by the Csurf middleware as expected.
POST request is protected by Csurf middleware as expected
To mitigate this, developers should do one of the following:
This code block demonstrates option 1 where the route is redefined to use the POST method.
GET request is no longer vulnerable to CSRF exploit
The next code block demonstrates option 2 where the GET method is removed from the ignoreMethods option.
The recommended solution is to change the route so that GET requests are not changing the application state. Applying the Csurf middleware inline to each route is the least-recommended solution as it increases the likelihood that a developer will accidentally omit the middleware from a sensitive route.