Software Integrity

 

ExpressJS: Preventing common vulnerabilities in the MEAN stack (Part 2)

ExpressJS: Preventing common vulnerabilities in the MEAN stack

Before diving into the latest post within our discussion on vulnerabilities in the MEAN stack, look back at the first two posts discussing MongoDB and ExpressJS (Part 1).

Client-side session storage (ExpressJS)

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.

ExpressJS: Preventing common vulnerabilities in the MEAN stack

Session cookie purged from browser after 15 minutes

ExpressJS: Preventing common vulnerabilities in the MEAN stack

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.

ExpressJS: Preventing common vulnerabilities in the MEAN stack

ExpressJS: Preventing common vulnerabilities in the MEAN stack

Client-sessions creation and duration time stamps used to invalidate the session server-side

 

Csurf and GET requests (ExpressJS)

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.

ExpressJS: Preventing common vulnerabilities in the MEAN stack

ExpressJS: Preventing common vulnerabilities in the MEAN stack

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.

ExpressJS: Preventing common vulnerabilities in the MEAN stack

POST request is protected by Csurf middleware as expected

To mitigate this, developers should do one of the following:

  1. Change the /secure/removeInvoice route to use the POST method
  2. Remove GET from the ignoreMethods option
  3. Apply the Csurf middleware inline to each route requiring protection rather than globally with use()

This code block demonstrates option 1 where the route is redefined to use the POST method.

ExpressJS: Preventing common vulnerabilities in the MEAN stack

ExpressJS: Preventing common vulnerabilities in the MEAN stack

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.

ExpressJS: Preventing common vulnerabilities in the MEAN stack

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.

Stay tuned for Part 4 of this series, exploring AngularJS, which will drop on the Software Security blog on May 10th.