Sep 5, 2019 · by Vlad Ionescu

CSRF Attack and Protection Mechanism

A guide to understand CSRF attacks and how to protect against them

The consequences of a malicious web attack can run deep, causing users to reach new breadths of annoyance and irritation. As attacks become smarter and abundant, it’s important to understand the various attacks that a user is susceptible to and how to protect themselves in the unfortunate chance they find themselves a victim of one.

What is CSRF?

According to OWASP (Open Web Application Security Project), 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. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response to the forged request. 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.” [1] 

Media coverage

This type of vulnerability has been spotted earlier this year by a security researcher on Facebook.com

“The cybersecurity expert “Samm0uda” discovered a vulnerability after noticing an exposed endpoint (facebook.com/comet/dialog_DONOTUSE/), which could be exploited to bypass the CSRF protections and perform various actions on behalf of the victim.” [2] So, it’s still a prevalent attack and it can happen to some of the biggest companies as well. 

How can a CSRF attack happen?

Outlined below, using a mock-up web application, we will present a flow in which a user registers into his favorite application and remains logged in. He receives a malicious link through a social media platform, email, etc., and clicks on the link to access. By accessing the link, the attacker does some sort of harm on the current logged in user, changing his login password. This is just a simple example that can be extrapolated to some more harmful attacks such as transferring user’s funds in the attacker’s account (if, of course, the site’s bank is susceptible to these kinds of attacks). 

Application structure and exposed functionalities

In the screenshot below, we’ve mocked-up a web application displaying a cars table along with some basic information. The URL points to localhost:8080. In the main menu, we can register and log into the application. The log in functionality has been developed using the Spring Security library, in which CSRF has been disabled in order to demonstrate the attack. The Spring Security library ships with the CSRF token enabled by default. 

First of all, since we’re just a guest on this site, let’s make a user and register ourselves. 

We will use john.smith@yahoo.com as the username and the StrongPassword as the password. Clicking on register, we’ll successfully register and we’ll be redirected to the login page. 

Before logging in, let’s check the database and see if our user has been created successfully. 

For the purpose of simplicity and demonstrating only the CSRF attack, we’ve let out the practice of not storing the password in plaintext. In a real life scenario, this should be stored as a salted hash. 

Let’s use our previously credentials and log in. 

We can see below the greeting message and also some personalized actions of what we can do since we are logged in (Change password and Logout). 

Let’s change our password. 

Notice that this screen doesn’t implement an extra-authentication mechanism, like entering the current password, in order to change it to a new one. This is another security flaw because will contribute in allowing CSRF attacks. 

We will change the password to StrongPassword2

Exploit the application

Now, let’s imagine we receive through email, or social media a link to a malicious website. The current malicious website has not been posted online but it can be done very easy by assigning it to a domain and then easily cause confusion by using bit.ly to hide the malicious link. Therefore, the victim won’t see the actual URL of the site. We will access the malicious site from our local host. 

See below the site accessed in browser after the victim clicked on the malicious link. 

The site consists of a simple html page displaying an image of a cat. There is nothing suspicious here, no “weird” action has to be performed by the victim in order to “do” something in order to trigger a malicious action.

Let’s examine the HTML for this page. 

You can see that inside the HTML body element we have a form tag pointing to our web application, most explicitly to our changePassword action inside the web application. If you wonder how the attacker knows in the first place this URL, it’s very simple. The web application the victim uses is also known by the attacker. He can login into the app and using it himself as a simple user. Therefore, he can create a user of its own, login into the application with that user and change its password after that. Doing these actions on his user and inspecting the Network tab in the browser, he can see the actual requests being made to the server. Thus, he can mimic the same requests but on a different user (the victim), if the victim is already authenticated in the application. More on that below. 

So, besides the URL action, the form also consists of a target attribute which is a reference to a HIDDEN iframe. Inside this iframe the actual request will be made, without refreshing/redirecting the current HTML page the victim is seeing. So, the request will be invisible to the victim. 

The form contains two hidden input elements with the same name as the ones from the web application (password, confirmedPassword). These names can also be found very easy, as explained above. They are part of the request body which can be seen by going to Network tab when you make the request as a simple user in the browser. Notice that in those hidden inputs, we change the user’s password to “hacked_password”. The actual line of code that will trigger this request to be made is present in the body tag, onload attribute. In there, we take the form element from the document and call the submit() function. So, when the victim accessed the page, besides displaying the actual page, it also resulted in: 

So, just by accessing a simple HTML page with nothing fancy in it and without implementing CSRF tokens, an attacker can compromise security and personal details of a legitimate user. In order for this attack to work, the victim has to be already logged into the application. This means that, every API call that will be made, will be done in an already authenticated context. If this is not the case, then the request performed by the attacker in behalf of the user won’t do anything, because, behind the scenes, the back-end will deny the request since the user is not authenticated. 

Mitigations

Users should enable CSRF token on the backend or develop some similar functionality on their own. “Synchronizer token pattern (STP) is a technique where a token, secret and unique value for each request, is embedded by the web application in all HTML forms and verified on the server side. The token may be generated by any method that ensures unpredictability and uniqueness (e.g. using a hash chain of random seed). The attacker is thus unable to place a correct token in their requests to authenticate them.” [3] 

Also, the token generated on the back-end is cryptographically related, like a pair, with the authentication cookie. 

Once the user is authenticated, it will be assigned an authentication cookie, a session ID (JSESSIONID in Java) that will be passed back to the server automatically by the browser, on each request, to ensure that the action performed in UI is a legitimate one. By enabling CSRF tokens, a unique randomly generated value is also sent back to the server on each request, value that is generated in relation with the auth cookie. You can use the analogy of a public-private symmetric-key algorithm. Once the two values end up in the backend, the CSRF token will be generated, “decrypted” based on the auth cookie and the library’s algorithm that generated it in the first place. If the CSRF token resulted matches the one sent from UI then the request is allowed, otherwise is not. Thus, the CSRF token cannot “go” without the authentication cookie. 

Below, you can see how our demo web application’s login page looks like with the CSRF token enabled on the backend. 

Inside the form element, a new hidden input appears with the name = _csrf and a randomly generated value. Since this value is random and uniquely generated with each request and in relation with the authentication cookie, this makes it impossible for an attacker to try to guess it. The request won’t work if this value is not present or it has an incorrect value. The attacker doesn’t know the authentication cookie value – this can be seen only by the legitimate user who is logged into the application – so, he cannot generate himself the CSRF token. Also, he should know the algorithm used to generate it. 

Accessing the attacker’s malicious web page again, won’t trigger the request for changing the victim’s password, it will just display a nice picture of a cat – which is always way better than having to deal with an attack. 🙂 

Article sources

[1] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
[2] https://hackercombat.com/facebooks-csrf-vulnerability-allows-attackers-to-hijack-accounts/
[3] https://en.wikipedia.org/wiki/Cross-site_request_forgery 

Vlad Ionescu

Vlad Ionescu

Java Software Engineer
Vlad Ionescu is a Software Engineer at Cognizant Softvision, based out of the Iasi Studio since 2014. Vlad holds a Bachelor's degree in Computer Science and a Master's degree in Marketing and Business Communication from AI. I. Cuza University.
Vlad Ionescu

Latest posts by Vlad Ionescu

Share This Article

Post A Comment