Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express CSRF token validation

I'm having issues with CSRF tokens. When I submit a form, a new XSRF-TOKEN is being generated but I think I'm generating two different tokens, I'm kinda confused. There's also a token called _csrf, so I see two different cookies in developer tools (XSRF-TOKEN and _csrf), _csrf doesn't change after a post.

What I want to do is to generate a new token for each post request and check whether it's valid or not. One thing I know that I should do it for security, but I stuck.

It has been a long day and I'm new into Express and NodeJS.

Here's my current setup.

var express = require('express')
  , passport = require('passport')
  , flash = require('connect-flash')
  , utils = require('./utils')
  , csrf = require('csurf')
  // setup route middlewares
  ,csrfProtection = csrf({ cookie: true })
  , methodOverride = require('method-override')
  , bodyParser = require("body-parser")
  , parseForm = bodyParser.urlencoded({ extended: false })
  , cookieParser = require('cookie-parser')
  , cookieSession = require('cookie-session')
  , LocalStrategy = require('passport-local').Strategy
  , RememberMeStrategy = require('../..').Strategy;


var app = express();

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.engine('ejs', require('ejs-locals'));
app.use(express.logger());
app.use(express.static(__dirname + '/../../public'));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(flash());
// Initialize Passport!  Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
app.use(passport.authenticate('remember-me'));
app.use(app.router);
app.use(csrf());

app.use(function (req, res, next) {
  res.cookie('XSRF-TOKEN', req.csrfToken());
  res.locals.csrftoken = req.csrfToken();
  next();
});

Routes

app.get('/form', csrfProtection, function(req, res) {
  // pass the csrfToken to the view
  res.render('send', { csrfToken: req.csrfToken()});
});

app.post('/process', parseForm, csrfProtection, function(req, res) {
  res.send('data is being processed');
});

send.ejs (/form GET)

<form action="/process" method="POST">
  <input type="hidden" name="_csrf" value="<%= csrfToken %>">

  Favorite color: <input type="text" name="favoriteColor">
  <button type="submit">Submit</button>
</form>
like image 265
salep Avatar asked Oct 10 '15 23:10

salep


People also ask

How is CSRF token validated?

CSRF tokens are only validated when the acting end user has a valid session Id. This meaning that in the instance of a public community or Force.com site, all users are Guest users. As of Winter 15, for security purposes, Guest users no longer had generated Session Ids.

How use CSRF token in Express JS?

CSRF Token The tokens are present in all forms as hidden fields. So, when the client proceeds to submit the form, it contains a validation voucher that confirms the user intended this action. To implement CSRF tokens in Node. js, we can use the csurf module for creating and validating tokens.

Does Express have CSRF protection?

Both frameworks have CSRF protection built in but don't understand each other without manual adjustments. Express is built on top of the connect framework which has a native csrf middleware. It generates a random string token that is unique for each user. The token is saved in the user's session on the server.


1 Answers

Based on the amount of code you shared, I will mention a few things that don't look quite right to me:

1 . You may need to swap the lines below so that csrf runs before the routes.

app.use(csrf());
app.use(app.router);

2 . The csrftoken setup needs to also be placed before the routes.

app.use(csrf());
app.use(function (req, res, next) {
  res.cookie('XSRF-TOKEN', req.csrfToken());
  res.locals.csrftoken = req.csrfToken();
  next();
});
app.use(app.router);

3 . You'll need to use locals.csrftoken in your form:

<form action="/process" method="POST">
  <input type="hidden" name="_csrf" value="<%= csrftoken %>">

  Favorite color: <input type="text" name="favoriteColor">
  <button type="submit">Submit</button>
</form>
like image 170
filype Avatar answered Oct 12 '22 18:10

filype