CSRF (Cross Site Request Forgery Attack)

Definition

Happen when we explicitly set the Cookies's SameSite attribute None

Example

  1. User logged into a banking website which does not set SameSite=Strict or SameSite=Lax.
    • Therefore, the user's cookies is accessible from any sites.
  2. Attacker create a malformed website and trick user to access the website.
    • The website automatically submit a banking transfer request to the bank using the user previously logged in cookies: Pasted image 20230806213624.png
  3. The user lost money

Solution

CSRF Token

Basic idea

We attach an unique token for each form we send to user. This is included by default in ASP.NET Razer framework.

In this case, when the user send the form we can then attach the csrfToken inside the form, for example:

Pasted image 20230807200014.png

It would be impossible for the attacker to guess the value of csrfToken beforehand, therefore will prevent CSRF.

Synchronised CSRF Token

Given the idea above, it's important to compare the CSRF token: the one from the client side and the one the server side has.

As a result, the server needs to store a CSRF token for each user session.

  • We want to store per session because sometimes when user click the Back button, storing per request will make the cookie invalid.
  • The CSRF token will be unique per session.

[!note]
For synchronised CSRF token, the token should not be transmitted using cookies. This is to minimise the vulnerability from cookies

We can transmit the token to client using a response payload as part of the respond like HTML or JSON.

For client to transmit back to the server we can use hidden form or request header.

  • It's recommended to use request header because it subject to same-origin policy

The synchronised CSRF token approach requires us to maintain the state of the token on the server. If we prefer a stateless implementation to prevent CSRF, we can implement the double submit cookie.

The idea is that we provide the CSRF token from server side to the client using HttpOnly Cookie — which cannot be forged by client side.

We then compare if the CSRF sent in the cookie is the same as the CSRF sent by the client (via hidden input or request).

Since the CSRF sent using HttpOnly is not forgable and not seeable from client, it's impossible for the attacker to forge this CSRF token.

However, a possible vulnerability is if the attacker using man-in-the middle attack, which then modify the HttpOnly Cookie in a way that the CSRF in the cookie is the same as the CSRF in the payload given by user

See: Bypassing CSRF Protections: A Double Defeat of the Double-Submit Cookie Pattern (owasp.org)

To address the problem above, we can sign our cookie with a secret key. As a result, it's impossible for attacker to know our secret key to create a fake encrypted CSRF.

We can set the SameSite=Strict or SameSite=Lax in Cookies header. This will prevent if the script triggered a POST request on behalf of the user.

As a result, when the attacker try to forge the cookie, it wouldn't be able to because it is not from the same site.