How Cross-Site Request Forgery Works
Tags: webdev, security, rails, tutorial
Published: 2022-09-14 03:43:44

A Cross-Site Request Forgery (CSRF) attack tricks authenticated users into performing a dangerous activity on the application, such as transferring funds, changing the credentials, granting access to some protected resource, etc. Since the users are authenticated on the application, it doesn't prevent them from performing this activity.

![CSRF Attack](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it48k2fadwhce3uf4sr2.jpeg)

The Open Web Application Security Project, or OWASP, describes this vulnerability as follows. 

> 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, etc. CSRF can compromise the entire web application if the victim is an administrative account.

### Example

Here's a scenario that demonstrates how a CSRF attack works.

**Step One:** An attacker creates a fraud request that performs some dangerous activity.
 
**Step Two:** The attacker embeds this request into a hyperlink or a form and posts these links in many places on the internet, where unsuspecting users are likely to click them, such as forum comments, images, email links, etc.

**Step Three:** A victim is logged onto the application (e.g. banking website) in one tab and opens the email in the other. Then they click the fraud link in the email. 

**Step Four:** Most web applications implement authentication using browser cookies. Cookies have nothing to do with tabs or windows -- they have to do with requests to a domain. Whenever the browser requests the web server for a domain, any cookies that the browser has for that domain will be sent in the request header. Since the user was logged into the application in the first tab, the browser sends the cookies from the request made from the second tab. 

**Step Five:** Upon receiving the request, the web application checks the cookies and authenticates the user. Now it's thinking you're performing this request. However, this is the forged request created by the attacker. This request can now do anything that your application allows to logged-in users, such as transferring money from the bank account.  

Now, you might think that clicking a link or opening an image will make a GET request, which is harmless. Well, the attacker can easily write JavaScript code that creates and submits a form on the fly upon clicking a link or visiting a web page.
 
Here's an example that creates a form making a POST request to update your bank email and submits the form whenever the page loads. 

```html
<form action="https://your-bank.com/user/email" method="POST">
    <input type="email" value="malicious-email@example.com">
</form>
 
<script>
    document.forms[0].submit();
</script>
```

Now, all the hacker needs to do is trick you into visiting the page while you are logged into your bank website. Once the page loads, it will submit the form to the bank's website, passing the cookies. The bank website will think you are a genuine user and updates the email address. 

## How to Prevent CSRF?

So the main problem behind the CSRF attack is that the server application is not differentiating between a genuine request (from the actual application) vs. the forged request that came from the attacker's code. 

> Only if there was a way for the server to identify the requests that came from the application, then it could reject all other requests that came from anywhere else. 

We can solve this problem by instructing the server application to insert a unique, random token inside each form. Now, when the form is submitted from the application, this token is sent along with it. Upon receiving the request, the server checks if this token is present and matches the token it has. If it's present and matches, it knows that the request came from a genuine user and is valid. It rejects the request if the token is missing or doesn't match. 

![Preventing CSRF using Auth Tokens](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5z9ca2tbo6p13bipc5t.jpeg)

Since the token is random, the attacker can't guess and insert it into their forged requests. Hence the server rejects all forged requests, keeping the users safe. 

This is how most web application frameworks prevent CSRF attacks, by using a token that verifies the authenticity. If you'd like to read more in detail about how Ruby on Rails does this, you can read this detailed article on my blog: [Preventing CSRF Attacks using Authenticity Tokens in Rails](https://www.akshaykhot.com/understanding-authenticity-tokens-in-rails/)

Hope this helps. Please let me know if you have any questions or comments. I look forward to your feedback.