2

I understand how Cross-Site Request forgery happens, but I'm very unclear about how to protect against it using a SPA(React) application.

For instance, my current strategy is to, on login, send a csrf token to the client as a cookie, the on the client, grab that cookie and include it in the req.body or in a custom header.

My express backend is using the CSURF package and will verify the token on any POST routes.

However, how is this safe? A malicious website can do the exact same thing, hit my log in, receive the token, add to token to header, and then do anything.

What is the proper way to protect against CSRF in a SPA where my API is separate from the server that sends my client application?

3

2 Answers 2

4

However, how is this safe? A malicious website can do the exact same thing, hit my log in, receive the token, add to token to header, and then do anything.

The malicious website could grab a csrf token, but as your server will have a different csrf token for each user session, it will be of no use to the malicious website.

To better understand csrf attacks, consider the following workflow:

  • a user login successfully on your website, creating a session server-side, and getting a session cookie client side that identifies the server-side session
  • this user now visits another site (malicious) that has an onload event that trigger submitting a form on your website, that is accessible only to logged in user. The form would look like this :

    <form method="POST" action="https://your.web.site/secured/transferFund">
        <input type="hidden" name="amount" value="1000"/>
        <input type="hidden" name="to" value="malicous_guy_account"/>
    </form>
    

    on submitting this form in an event, it :

    • will be totally invisible to the end user
    • work because the client is logged in on your website, and the session cookie will be used for this http request automatically

So how the CSRF token helps ?

It is not stored in a cookie, but either directly in a hidden form field, or in a header, both location cannot be scanned by the malicious website.

So now, when the malicious website tries to submit the previous form, the csrf token is missing or invalid, and will be rejected server-side as not authorized.

For that to work, you need :

  • different token for each user session,
  • to tie the token to the session lifecycle,
  • to keep it away from cookies,
  • that everything that changes state server side, is behind a POST action
  • that every POST action has its CSRF token validated
1
  • Thank you for this! It was very helpful and with the two answers solves most of my confusion. Commented Sep 23, 2019 at 22:13
1

It's possible that your understanding is missing a key piece of information: the CSRF-protection token is unique and unpredictable for each user session. An attacker that logs in with their own credentials will not receive the same anti-CSRF token that the would-be victim will. A request forged by the attacker but sent from the victim's browser will have the attacker's anti-CSRF token in the request body/header, but will have the victim's anti-CSRF token in the cookie. Because the tokens are different, the server should reject the forged request.


Do note that this pattern (called "double-submit cookie", where the value is submitted both in the body and the cookie of the request) is not especially secure. While it's easy on the server and load-balancer friendly, because the server doesn't need to store state (such as "user X has anti-CSRF token Y"), cookies have a weaker same-origin policy than most modern aspects of the web.

In particular, if an attacker has a man-in-the-middle position on the victim, a network attack can be used to make the victim's browser load the page over HTTP (even if the server won't respond over HTTP; the attacker just intercepts the request and forges the response) and set the anti-CSRF cookie with a value of the attacker's choosing. Because the browser will send cookies that were set over insecure connections along with secure requests, the server will receive the cookie the victim set.

This is a risk any time the attacker can plant a cookie in the victim's browser for a particular site. Because the attacker knows that cookie's value, the attacker can then forge requests using that token, and they'll be accepted. The most common way of doing this is probably via the MitM attack described above. The best protection from that is HSTS (HTTP Strict Transport Security), which will prevent the browser from even attempting to load your app over an insecure connection.

2
  • Wow, thank you for this. It actually answers exactly the problem I was struggling with. And means my CSRF solution is mostly complete. Commented Sep 23, 2019 at 22:13
  • You're welcome! Yeah, one vulnerability I've seen in attempts at CSRF protection is reusing the token across users, or making the tokens predictable (for example, a simple incrementing counter, timestamp, or the output of a non-secure PRNG). Also, note that I'm adding another edit you should be aware of.
    – CBHacking
    Commented Sep 24, 2019 at 0:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .