Preventing CSRF with an Express API and a React frontend

Viewed 1720

I have been reading around CSRF for the past few days and feel like I have a good grasp on what it is and how to prevent it. I am building a small Express/React application that will have a secure admin area for updating the app content and I want it to be protected from CSRF.

I understand that it is common for the server to generate the CSRF token and then send it to the client along with the view (page) that has been requested (the token can then be hidden in a HTML form input tag). However, my Express API does not serve HTML, it is a REST API that only returns JSON data. The UI is built with React, running on a different port from the server.

My question is; Where do I securely store a token generated on the server?

For example, if I log in as admin by hitting '/api/login', generate a token, and send it back to the client in the API response, what should I do with it now?

The original plan was to use Redux to store the token but from reading this post Is Redux secure?, this does not sound ideal.

I considered using React env variables but have also read that these are exposed in the build.

Obviously localStorage is also a bad idea...

I am really struggling to find a solution to this problem using the tools I am implementing i.e. Express/React

Any help, links, advice, criticisms would be appreciate, I want to learn to build apps with security in mind

1 Answers

I understand that it is common for the server to generate the CSRF token

The server needs to generate two CSRF tokens

and then send it to the client along with the view (page) that has been requested (the token can then be hidden in a HTML form input tag).

One token is commonly sent as a cookie, another can be sent as HTTP header. It doesn't need to be sent inside HTML body as a HTML form input tag (or any other part of the body) though it can be sent this way.

My question is; Where do I securely store a token generated on the server?

You don't have to store a token on the server. You can but you don't need to.

The original plan was to use Redux to store the token

The Redux store is on the client, in browser's memory. In theory one React component (that extracts the second CSRF token from server response) can temporarily store the token in the store so that another React component can get it from there and put into the next request before it's sent to the server.

Obviously localStorage is also a bad idea...

Yes

Any help, links, advice, criticisms would be appreciate, I want to learn to build apps with security in mind

Links
With Express is very common to use this middleware. The steps can be found here.

Criticisms
This is strictly speaking off topic in the context of CSRF related Q/A, but ...

The UI is built with React, running on a different port from the server.

That hints to the possibility of using react-scripts which start webpack-dev-server. It's fine for development, not good for deployment in production. However this is a separate topic, serving React app's build artifacts (.html file, script bundles) to webclients has nothing to do with CSRF attack and its mitigation.

I want to learn to build apps with security in mind

Then you might consider using one webserver instead of two (frontend to serve React app and backend to serve API responses). Using one server results in production deployment which is not only less complex and costly, but also more secure because two servers have larger attack surface and with one server you don't need to weaken security by using CORS.

Related