DEV Community

Poorshad Shaddel
Poorshad Shaddel

Posted on • Originally published at levelup.gitconnected.com on

Prevent CSRF Attacks in Node.JS application

In this article we are going to see why we should know about this attack, what is this attack exactly, perform a simple CSRF attack to know how it works, and finally how we can protect our application against CSRF attacks.

Why we should know about CSRF attacks?

Before starting to see what is this attack we should know how hazardous this attack could be.

If someone performs a successful CSRF attack on a normal user (who does not have administration permissions), that person is able to do state-changing requests like deleting the account, transferring funds, and changing the email address.

If the user has administration permissions attacker can compromise the whole web application.

So I think we have enough clues to dig more about this attack. Let’s see what is a CSRF attack exactly.

What is a Cross Site Request Forgery (CSRF)?

Based on OWASP: Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they’re currently authenticated.

This attack is also known as one-click attack or session riding

Usually these attacks are combined with social engineering attacks. For example, they send me an email that contains a link that says you won 10000$ in a lottery(that you know you didn’t participate :) ) and we need to get your information, please click on the link below. That link is going to do something with another website(which is your website and here specifically a Node.js app).

This is the process of a CSRF Attack :


How CSRF Attack is done

The best way to understand this attack is to perform one simple CSRF attack.

Simple CSRF Attack

We have a Node.JS application and it has two routes that let users transfers money with a post request:

https://medium.com/media/81369f13d7059c85b9da271ca3044a29/href

We have two routes. First one is GET /transfer which is a form that let us transfer money and the second one is POST /transfer that authenticate user with a simple function named isAuthenticated and transfers money to the destination.

isAuthenticated function is just checking that if a cookie named session is sent with the headers or not and the session is “valid_user” or not.(This is not what we do in production but you can find that easily in some libraries like passportjs)

If user is authenticated we can perform a transfer operation and if the user is not authenticated we get a bad request in response.

Create a Cookie to be an authenticated user

We didn’t implement the sign in process here and instead we can manually generate a cookie that does the work:

Run your Node.JS app using this command:

node server.js
Enter fullscreen mode Exit fullscreen mode

Now the app is running in port 4002

We need to go to this route: http://localhost:4002/transfer to check the app.

Before adding any cookie if we try to post this form:


HTML Form without CSRF Token

We get this result:


Result of unauthenticated user

In order to manually generate cookie you need to open your browser developer tools by right clicking and clicking on inspect and after that opening console tab and running this line of Javascript code:

document.cookie="session=valid_user";
Enter fullscreen mode Exit fullscreen mode

After this we have a cookie in localhost domain and backend consider our user authenticated and if we post that form again we get this result:


Result of authenticated user

So at this point we are a authenticated user and we are able to transfer money by posting a form to this route: POST /transfer

Create an Email that contains a Form

A simple way to send an email with desired HTML we can open Gmail website and after that we need to right click on the body of email and click on inspect now we can edit body of email by right clicking on the element and choosing edit as HTML . Here we can enter our HTML elements.

This is the body of email we want to send to our victim:

https://medium.com/media/f5b273ac5a00d3bdcec93127765adbe7/href

As you may notice we have two hidden inputs and a button to post the form. Also in the input with the name of account we can see that we entered attacker_wallet .

Here is how you can edit the email body:


Adding HTML elements to the body of email

Finally this is the email that victim receives.


The email that trigger CSRF attack

Now if I(as an Authenticated user) click on the button it redirects me to a new tab in the browser and money transfer to the attacker wallet is done:


Victim clicks on Button in the body of email

Now that you know how CSRF attack is working it’s time to see how we can stop this

Prevent CSRF Attacks by Token Based Mitigation

This is one the most popular and recommended methods we can use to prevent CSRF Attacks.

We are going to generate a token server side and they can be generated once per user session or for each request. Per-request tokens are more secure than per-session tokens as the time range for an attacker to exploit the stolen tokens is minimal.

As OWASP document mentioned:

CSRF tokens should be:

  • Unique per user session.
  • Secret
  • Unpredictable (large random value generated by a secure method).

Here we are not going to implement a CSRF Protection library. We use csurf package to generate CSRF Tokens and also validate them on the backend side.

This library is not maintained anymore but fortunately it does not have any vulnerabilities at the time of writing this article.

We are going to change our back-end like this:

https://medium.com/media/8eb50759cbfa8379492b6c4e42477c67/href

As you can see in line 6 we added csrfProtection and cookie is true here and it transfer csrf token in the cookie too.

In line 12 we added csrfProtection as a middleware and after that we are able to generate a CSRF Token for the form.

We need to pass the CSRF token in _csrf input.

Now we can validate this token in line 26 by just using csrfProtection middleware.

By default if you are storing user session in session cookie, CSRF Protection binds its tokens with the user session which can make your app more secure.

Let’s see the new form and CSRF Token:


CSRF Token

Now it’s time to click on the link again and after doing that we will see this:


Invalid CSRF Token

Weaknesses in CSRF Token Implementations

Validation depends on presence of token

In some applications validation process is skipped if the token does not exist.

CSRF token is not associated with user session

If you do not bind CSRF token with user session, someone can use another person’s CSRF token to perform malicious action. In the library we used if pass the session in cookies as session the library binds it to CSRF token. If you are storing session with a different name you need to set sessionKey in the config of CSRF protection.

Token validation changes with HTTP method

You should check that your token validation work with all HTTP methods.

CSRF token is copied to the cookie

You must keep a record of tokens that are already in use. Instead, the attacker can copy the request parameters associated with each token into the user’s cookie. In this setup, the attacker can create a cookie that contains a token using the application’s expected format, place it in the user’s browser, and then execute a CSRF attack

Conclusion

CSRF attack is one of the attacks that can affect many of users by sending emails and performing social engineering techniques so it is vital to understand this attack and prevent this by simply using CSRF Token. If you want to make it more secure you need to use best practices of generating this token.


Top comments (0)