Going surfing – Protect your Node.js app from Cross-Site Request Forgery
Time to read: 5 minutes
Cross Site Request Forgery aka CSRF/XSRF (read C-Surf). They are used by attackers to perform requests on behalf of users in your application without them noticing. Let’s look at how they can pull this off and how we can protect our applications from these type of threat.
One classic attack when working with web applications isLet’s talk theory
Before we can prevent CSRF attacks we need to understand how they work. Typically these attacks are executed on the functionality of web applications that use form-based submissions like POST
requests and cookie-based authentication.
An attacker places a hidden form into their malicious page that automatically performs a POST
request to your page’s endpoint. The browser then automatically sends all the cookies stored for that page along with the request. If a user is logged into a current session, the attacker could, for example, post a message on behalf of the logged in user without them noticing. The attacker never has to have access to the page’s cookies for this.
We can protect ourselves from this attack by using CSRF tokens. The concept is that when the browser gets a page from the server, it sends a randomly generated string as CSRF token as a cookie. Later, when your page performs a POST request it will send the CSRF token as a cookie and also in another way such as a parameter in the body or via an HTTP header like X-CSRF-Token
.
An attacker will not be able to reproduce the same behavior with their hidden form since they won’t be able to access the cookie to retrieve the value and send it along with their malicious POST request.
This concept can be implemented in pretty much any web application but let’s look at how we can implement it in an Express application.
Getting the board ready
First we need an application to see how the CSRF vulnerability works in reality and how we can protect ourselves from it. If you already have an existing Express application, feel free to perform the following steps on it. Alternatively follow the next steps to set up our demo application.
Before we get started make sure you have Node.js and npm or another package manager installed. Start the new project by running the following commands in your terminal:
Next create a new file called index.js
and place the following code into it:
Start up the application by running:
Visit http://localhost:3000 and you should be greeted with Hello World
and a small form below it.
Dangerous Water
The current server has two endpoints. One is our main page that is served when you go to http://localhost:3000/. The other one is a POST
endpoint on http://localhost:3000/entry. When we fill out the form and press Submit
we’ll make a POST
request to this endpoint.
Try it by entering some text in the form and press submit. You should see the message returned and it should also be logged into the console of your running server.
Unfortunately an attacker is able to perform the same request on their page. To simulate that we implemented the same form on a page on Glitch. Visit csrf-attack.glitch.me, type in a message and press submit. The behavior will be the same as submitting the form on the localhost
page. It will transfer the message and along with it any cookies that are set.
In this case we created a form that the user can submit by themselves but it could have been a hidden form that auto submits with malicious content. Let’s see how we can protect our page from this.
Going csurf
ing
There are multiple modules that help you implement CSRF tokens in your application. One of them is csurf
. Install that module along with the cookie-parser
dependencies by running:
Both of these modules are middleware that can alter the behavior of a request in Express. We are already using body-parser
to parse our POST body to retrieve the message. Additionally we’ll use it to check for the _csrf
token. The cookie-parser
middleware will check that the token is available in the cookies and csurf
will be the automatic guard for any POST, PUT, PATCH or DELETE operations by checking that the _csrf
token is present in both the cookies and the request body and that they match.
Add the following code to your index.js
file to configure the middleware:
Restart your server and navigate to http://localhost:3000. Enter some text in the input box and hit Submit
. You should see the message appear in the console and be greeted in the browser with a message like the one below:
Now switch back up to the demo page on Glitch and enter a message there. When you hit submit you’ll see that the request failed and that the message won’t appear in the console. The _csrf
cookie is transferred, however, the page doesn’t send the same value in the POST body as _csrf
value. As a result, the request is blocked by the csurf
middleware and we have protected ourselves from CSRF attacks.
What’s next?
We’ve seen how to easily integrate CSRF tokens into a Node.js based application with server-side rendered code. However, using CSRF tokens with your front-end frameworks and libraries is just as easy. Since we are sending the token as a cookie, you can just as easily read it and send it as a header with your async requests later. In fact Angular’s HttpClient
has this feature already built-in.
To learn more about how you can secure your Node.js applications make sure to check out my blog post about Securing your Express app. Additionally you should check out the OWASP page as it covers a wide range of security related topics.
If you have any questions or any other helpful tools to improve the security of your Node.js web applications, feel free to ping me:
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.