When you research web application security you will come across Cross-Site Request Forgery (CSRF). This attack vector is taking advantage of cookies, but in a preventable way. In this post we’ll discuss what the attack is and how it can be prevented. We’ll also discuss Angular’s XSRF feature, which helps you prevent attack. It requires cooperation from your server, and we’ll explain what you need to do.

Note: Angular uses the acronym XSRF, but this is synonymous with CSRF.

What is Cross-Site Request Forgery (CSRF)?

Most attacks focus on stealing your cookies because nearly every website uses cookies as a form of authentication. The setup is this: when a user logs into your server, you set a cookie in the browser. This cookie contains a unique ID which is a link to the user’s session information in your database. The browser supplies this cookie on future requests, and the server knows who you are.

On the surface this sounds not-so-bad, but here is the catch: the web browser can be tricked into making requests to your server, even if the end-user didn’t perform the action themselves.

How is that possible? This attack exploits the default nature of the HTML parser in your browser. Imagine that you run a store at www.mystore.com. Your store has an API that allows users to make 1-click purchases. That API uses a URL that requires the user to be logged in (to have a cookie session), and looks like this:

Now imagine that there is a malicious person that wants to exploit your Buy API and cause a headache for your users. This malicious person carries out their attack by making posts on websites and social media that contain an image link that looks like this:

Now imagine a customer who is logged into your site, who is visiting one of the pages where this link has been placed. When their browser encounters this tag it will automatically makes a GET request to the URL (because it naively wants to show the picture to your customer). When it does this it automatically sends along the cookies for www.mystore.com with the request. Thus, the server thinks your customer is logged in and completes the 1-click purchase for the customer!

This is pretty disturbing, as the customer has no idea that this has happened – they are simply surfing the web as normal and aren’t aware that this request has been made.

CSRF Mitigations That Don’t Work

Before we get into the proper solutions for this problem, I want to enumerate two common approaches that don’t actually solve the problem. I mention these because I see these solutions on the interwebs, but they are wrong:

  • Using POST Requests. It is sometimes thought that using proper form-based POST requests will mitigate this attack, but that is not true. You can create a form on another website and point its action URL to your site, and the browser will do the same thing: make the malicious request, with cookies.

  • Using HTTP-Only or Secure cookies. While you definitely should use these flags on your session cookie, they don’t implicitly stop the attack: the browser still sends the cookies to your domain when a request is made to your domain. Your server does not know if this is a real user or an attack.

With that out of the way, let’s move on to the important discussion: how do we stop this for reals 🙂

How To Prevent CSRF

Preventing this attack requires a knowledge of where the request is coming from in the browser. We want to ensure that the request was triggered by an explicit action from a user who is using the JavaScript application on our website.

We can achieve this by relying on a set of rules that browsers respect, called the Same-Origin Policy. This policy asserts that certain sensitive operations are performed by JavaScript code that is running on our website, not some other website.

One of those operations is the ability to read cookies. While the browser will automatically supply your cookies for the domain of the request, there is one useful limitation: the JavaScript code that is running on a website cannot read the cookies of other websites. We can leverage this to create our CSRF solution.

Because JavaScript can only read cookies from our domain, we will store a second cookie on our domain that contains a unique token. This is the CSRF Token cookie. This cookie must be created when the user is logged in, and should contain a random, un-guessable string that is associated with the user’s session ID (for future lookups).

Every time the JavaScript application wants to make a request, it will need to read this token and send it along in a custom HTTP header. Because these operations (reading the cookie, setting the header) can only be done on the same domain of the JavaScript application, we can know that this is being done by a real user who is using our JavaScript application.

A passive image tag or malicious form post, on another site, would not be able to do these things. If your server sees a request that is missing the custom header, or the token in the header is not the one that is associated with the user’s session, your server should reject the request.

Leveraging Angular’s XSRF Feature

Angular packages the CSRF token approach, making it simpler for us to implement. For every request that your Angular application makes of your server, the Angular $http service will do these things automatically:

  • Look for a cookie named XSRF-TOKEN on the current domain.

  • If that cookie is found, it reads the value and adds it to the request as the X-XSRF-TOKEN header.

Thus the client-side implementation is handled for you, automatically! But this does leave the server side pieces in your hands. You will need to do the following parts:

  • During login: create the CSRF token (with a random, un-guessable string), and associate it with the user session. You will need to send it on the login response as the XSRF-TOKEN cookie.

  • Assert that all incoming requests to your API have the X-XSRF-TOKEN header, and that the value of the header is the token that is associated with the user’s session.

That’s it! With a little bit of backend work, you now have a strategy which protects you from CSRF attacks.

Go Forth and Secure All the Things!

My goal for this post is to demystify what CSRF is, and how Angular tries to help you with a solution. CSRF is just a small piece in the web-application security puzzle. For more information, please see the other posts that I have written on this subject:

Token Based Authentication for Single Page Apps (SPAs)

Build Secure User Interfaces Using JSON Web Tokens (JWTs)

-r out