Search code examples
node.jsexpresscsrfcsrf-protection

How to resolve issue with handling csrf with multiple tabs in express/nodejs?


I built CSRF protection in my nodejs/express application with the following config:

var app = express(),
    cookieParser = require('cookie-parser'),
    session = require('express-session'),
    csrf = require('csurf');

app.use(cookieParser());
app.use(session({
    , saveUninitialized: true
    , resave: true
    , store: new MongoStore()
}));

app.use(flash());

And with the following login form:

<form action="/process" method="POST">
  <input type="hidden" name="_csrf" value="{{csrfToken}}">
  <button type="submit">Submit</button>
</form>

The problem arives when user opens two browser tabs and end of the story is getting EBADCSRFTOKEN error at this line:

Let's see the following case:

  1. User opens the form above in two separate tabs.
  2. In first tab he do logout and signin again.
  3. Then switches to second tab, click submit and get EBADCSRFTOKEN error.

I need to point that I destroy my session in logout route:

app.route('/auth/signout')
    .get(function (req, res, next) {

        return req.session.destroy(function (err) {
            if (err) return next(err);

            return res.redirect('/');
        });
    });

Because that fact that I destroy the session I destroy the secret also key that stored there. So this destroing leads to invalid token on second tab and EBADCSRFTOKEN error.

I need to resolve this case somehow. What you do in this case? Show popup to reload the page or reload page automatically?


Solution

  • The csrf token should be set and retrieved from cookie before form submission. Suppose, you open tabA with csrf C1. Once you open tab2, the csrf changes to C2. But, if this is set in the cookies, fetching csrf from cookies in tabA will give C2 as csrf token.

    Same thing can be concluded with session->logout->new_session. Save and fetch everything from the cookie. Since you logged in after a logout in tab2, tab1 will have cookies of tab2 and also the csrf token.