Cross-Site Request Forgery (CSRF)

In this chapter, we are going to learn about cross-site request forgery (or also called CSRF).

Type of vulnerability: Client-Side

Chances to find: Common; CSRF is part of “Broken Access Control” ranked #1 in the “OWASP Top-10 Vulnerabilities

TL;DR: A CSRF vulnerability enables an attacker to trick a victim into performing an unintended action. The targeted person has no idea about a specific click they have performed.

What is cross-site request forgery?

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. With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker’s choosing. If the victim is a normal user, a successful CSRF attack can force the user to perform state changing requests like transferring funds, changing their email address, and so forth. If the victim is an administrative account, CSRF can compromise the entire web application.  (src: OWASP)

Let’s have a look at an example. You are logging in to your banking app and you want to transfer money to your best friend.

You probably need your friend’s IBAN (international bank account number), an amount you want to send and some nice words. An example HTTP request could look like this:

POST /onlinebanking/transfer/funds/ HTTP/1.1
Host: example.com
Content-Length: 92

recipient=mybestfriend&iban=BE71096123456769&amount=100&message=thanks+for+paying+for+dinner

A couple of days later, the money would land in the account of your friend and everything is good. If it was not for an attacker who exploited you at the same time, sending 1337€ to his own account. So let’s see how he is doing that. First, he needs to set up a custom HTML page and host it on his server:

<html>
  <body>
    <form action="https://example.com/onlinebanking/transfer/funds" method="POST">
      <input type="hidden" name="recipient" value="attacker" />
      <input type="hidden" name="iban" value="BE13371337" />
      <input type="hidden" name="amount" value="1337" />
      <input type="hidden" name="message" value="thanks+for+donating+to+the+attacker" />
      <input type="submit" value="automated" />
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>

Basically, the attacker creates a form that only shows a button saying “automated” (line 8). This button is immediately clicked in an automated fashion by the included script in line 10 as soon as this website is visited.

If the victim is logged in into the banking app, he will have a session cookie stored in the browser’s cookie jar. If the victim then visits the attacker’s page, a request initiating a money transfer is made and the browser automatically adds the valid session cookie. At this point, the attacker has successfully transferred money to his own account.

The impact of cross-site request forgery!

CSRF is very much dependent on the application, the attacker is trying to exploit. Only if the vulnerable application has some functionality that would harm a victim if arbitrarily used by an attacker, there is realistic impact. Next to the example shown above, you could think of functionality to e.g. order a product to a specific address, change your user data, post to social media platforms, etc.

Even though CSRF requires user interaction the impact can be quite severe like for example an account takeover. The impact of CSRF is limited to the functionality of the application (changing data, creating/placing content, …).
An example of CSRF with no real security impact is adding items to someone else’s shopping cart. This also goes for login & logout CSRF, but that doesn’t mean they can’t be used to chain bugs to achieve real impact.

Here are some public write-ups of CSRF vulnerabilities exploited in the wild:

How to prevent cross-site request forgery?

There are various different ways to protect your application against CSRF. Start with checking if the web development framework that you are using has a dedicated capability to protect against CSRF. If not, make sure to implement the following mechanisms:

  • Send a CSRF token for every single HTTP request that changes state and validate it on the server-side

  • Use the Same-Site cookie attribute to additionally secure your cookies against misuse

Additional reading on CSRF prevention:

Additional resources:

Let’s have a look at a video example of a CSRF vulnerability:

Let’s have a look at another video, where we are going to bypass a basic CSRF protection mechanism:

This video by PwnFunction gives a very good visual explanation of CSRF:

Following links are valuable to learn more about CSRF: