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.
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.
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 🙂
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.
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-TOKENon the current domain.
If that cookie is found, it reads the value and adds it to the request as the
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
Assert that all incoming requests to your API have the
X-XSRF-TOKENheader, 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.
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: