Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to secure my react app api with csurf?

I am trying to add csrf protection to my react app but I am getting an error Invalid token all the time

import bodyParser from 'body-parser';
import cookieSession from 'cookie-session';
import passport from 'passport';
import csrf from 'csurf'
import config from '../../config'
import AuthRoutes from "./routes/AuthRoutes";

/* Test only */
import cookieParser from 'cookie-parser';


const session = cookieSession({
    maxAge:24 * 60 * 60 * 1000,
    keys:[config.COOKIE_KEY],
    name:'authentication',

});



export default app => {

    app.use(bodyParser.urlencoded({
        extended: true
    }));
    app.use(bodyParser.json());
    app.use(session);
    app.use(passport.initialize());
    app.use(passport.session());

    /* Test */
    app.use(cookieParser());
    app.use(csrf({ cookie: true }));

    app.use(function (err, req, res, next) {
        if (err.code !== 'EBADCSRFTOKEN') return next(err)

        // handle CSRF token errors here
        res.status(403)
        res.send('form tampered with')
    })

    /*Passport Config*/
    require('../../services');

    /* Register, Login these are routes i want to protect */
    AuthRoutes(app);

}
like image 330
Nane Avatar asked Dec 31 '19 19:12

Nane


2 Answers

You need to:
1. Configure csrf library on the server. This ensures the library will send the first piece of data attached to the server responses.
2. Use csrf library on the server to generate the second piece of data and attach it to the server response (e.g. HTML form sent to the client). After this step is completed the server response will carry two pieces of CSRF data.
3. On the client take the second piece of data and insert it into the request you are about to send (e.g. the form you are about to submit).

Step 1
So far only the step (1) has been completed. You asked the csrf library to send the first piece of data as a cookie. You could have used a better configuration:

app.use(csrf({cookie: {
    httpOnly: true,
}}));

It ensures the browser won't allow any JS on the client to touch the first piece of data inside the cookie which is good because there is no legit reason for any script to know what is inside this cookie. Later on, in production and when you use HTTPS, you can optionally add secure: true to the above configuration to make the server refuse to send this cookie over connections that are not secure.

Step 2
To get the second piece of data call csrfToken(). The csrf middleware added another property to Request object for your convenience so it can be called like this: const secondPiece = req.csrfToken(). You can put the second piece of data into the server responce in any way or manner you like: into another cookie with an arbitrary name (except for the _csrf name already taken by the step 1 cookie) or into HTTP header named as you like.

For example this code will put it into another cookie:

res.cookie('XSRF-TOKEN', req.csrfToken());

Step 3
On the client write JS to get the second piece of data and put it into one of the predefined places/locations (inside the request to be sent to the server) where csrf middleware searches for it by default.

like image 162
winwiz1 Avatar answered Sep 20 '22 02:09

winwiz1


Just in case, any solutions doesn't work.

I just had days of debugging caused by incorrect naming of the cookie. Make sure to name your cookie XSRF-COOKIE(take note it uses - symbol) because I incorrectly named mine using underscore XSRF_COOKIE and this bit my ass for days.

like image 38
The.Wolfgang.Grimmer Avatar answered Sep 24 '22 02:09

The.Wolfgang.Grimmer