DEV Community

Charlie
Charlie

Posted on • Updated on

Who's riding with you? An introduction to CSRF

Picture the scene: you've just created your first web app with all the bells and whistles you dreamed of. Your CSS is on point, you've wrangled with CRUD operations and now your users' login is authenticated by a cookie that's saved in their browser. You are flying high and are ready to share your creation with the world. They will love it as much as you do.

Before you do that, my friend, hold your horses for a minute. There's one tiny thing you might have forgotten to defend against: CSRF [pronounced sea-surf. Also known as XSRF, also known as session riding. This bad boy goes by many different names]. This mash of letters stands for Cross-Site Request Forgery. Ignore it and you leave your users open to a whole world of pain and data theft.
And nothing ruins the User Experience like your account getting hacked.

So what is Cross-Site Request Forgery/ CSRF/ XSRF?

CSRF is a type of attack that exploits a trusted user's privileges on a web application by sending unauthorised commands that alter the server's state without the user's knowledge. In other words, the attack makes the user unintentionally carry out an action. It does this by exploiting the fact that the user is already logged into and trusted by a web application. All web applications that perform commands or tasks without requiring users to re-authenticate themselves and authorise these commands are vulnerable to CSRF attacks.

One example of this is from 2006 when Netflix sent DVDs to peoples' homes. A CSRF vulnerability allowed attackers to change account shipping addresses and remotely add films to users' rental queues. So attackers could have the film of their dreams sent to their PO box of choice. They could even lock users out by changing their login and password details.

With the right CSRF, an attacker can do anything from sending an e-card to buying shares in a company to hacking into wind turbines. To make matters worse, users are unable to completely protect themselves from CSRF as they can't alter applications' inner architecture. So while user-side browser extensions like CsFire can remove authentication from cross-site requests, they only reduce the attack window.

Only you as an application developer can fully protect your users.

Common types of CSRF attacks

CSRF vulnerabilities might sound like scaremongering, but CSRF has the dubious honour of being one of OWASP's top 10 Security Risks in the last decade. Once an attacker has identified a potential target, launching an attack is as easy as embedding a JavaScript object, HTTP object or even an HTML image tag into an email or website. It is so simple that a bot can do it.

In fact there are bots out there that are created to exploit these vulnerabilities.

To show you just how easy it is to exploit a CSRF vulnerability, here are a few of the most basic attack methods:
<img src="https://vulnerable-bank.com/transfer?amount=&pound1000000&amp;to_accountnumber=12345678"/>

<script src="https://vulnerable-account.com/change?username=i_hate_cocopops;to_new-username=cocopops_are_best" />

<a href="https://vulnerable-investment-company.com/invest?amount=1000000&amp;to_company=you-never-heard-of" >Read more!</a>

<form action="https://vulnerable-bank.com/transfer.do" method="POST">
<input type="hidden" name="account" value="YOURS"/>
<input type="hidden" name="amount" value="1000000"/>
<input type="submit" value="Download Animal Crossing: New Horizons for FREE!"/>
</form>

Three ways to prevent CSRF attacks

1) Keep your JSONs secure

If your JSON files are top-level arrays, they are vulnerable to a JavaScript insertion such as:
<script src="https://email-provider.com/user.json"></script>

This accesses and sends the potentially sensitive information contained within the top-level JSON back to the attacker.
JSON objects are less vulnerable than JSON arrays:
{
"user": [
{
"username": "TonyCat"},
{"password": "d0oDOOd00DOOd00DOO"}
]}

If the JSON page does not need to be accessed directly by a URL, you can also add a tiny bit more protection by allowing only POST requests in place of GET requests. However, it is still possible for malicious actors to access content using well-crafted POST requests buried inside an HTML form.

2) Use UI-based defence

CSRF attacks exploit the fact that users are already authenticated (whether by browser, cookie or certificate). Forcing your user to re-authenticate themselves before performing actions prevents them being carried out without the user's knowledge.

CAPTCHA is a common way of re-verifying a user before security-critical operations such as transferring funds or changing sensitive data. If the request is a legitimate user request, the user will be able to respond to the CAPTCHA challenge. But if the request originated with malicious code, it will be blocked.
Another option is to send a one-time token to a mobile number or e-mail address associated with the user's account. Bear in mind that this approach does affect the flow of the user's experience and so should be used sparingly. Imagine the frustration of having to re-verify your account every time you wanted to watch a video on YouTube!

3) Double submit your cookies and store them securely

Twice as many cookies brings twice as much joy! First of all, make sure your session cookies (and any containing sensitive data) are tagged as HTTPONLY. This stops the cookie ever being revealed accidentally in a cross-site scripting error. (Which is a topic for a whole other post.)

Now we need to add a CSRF token to any pages that change the server state. Examples of this are changing user details, transferring funds, or submitting forms. The token should stop an attacker from making an HTTP request that will fool the victim's browser into falling victim to a CSRF attack. Some frameworks have CSRF protection built in, but others do not.

If, for example, you are using Express then you will need to install a middleware package like csurf which will generate a CSRF token. If you cannot find CSRF token creation and validation middleware that you trust, then use a pseudo-random number generator (PRNG for short) to generate a cryptographically secure token that contains a timestamp.
Send the CSRF token as a session cookie, then store the CSRF token as a hidden value in a custom request header for double security. As browsers do not normally allow custom headers to be shared across different domains this will add an extra bit of security to the CSRF token.

When a user requests a page that changes server state, the server checks the session cookie against the value submitted with the form. If they do not match, the form's action is disregarded. If they match then you're in business.

Summary

Hopefully you understand what CSRF is, and how to defend against some of the most common Cross-Site Request Forgery attacks. Don't feel disheartened at how vulnerable your newly-created app may be to CSRF. Everyone from Google to UberEats has had or continues to have exploitable CSRF vulnerabilities, so you've been in good company. As recently as December 2018, UberEats had no CSRF protection at all.

As with all security methods, it's easy to get into good habits when you know how to defend against risks. Now go on and get your app out there!

Top comments (2)

Collapse
 
helen8297 profile image
Helen Kent

You've done some mega research there Charlotte - thats seriously impressive. Well done!!

Collapse
 
concatermayte profile image
Charlie

Thanks Helen! Definitely don't have your way with words, but it was fun to find ways of explaining it :)