Web Security 10 — CSRF

Brian Shen
The Startup
Published in
5 min readMay 18, 2020

1 Intro

CSRF, Cross Site Request Forgery, 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.

2 Review Referrer Sample

In Web Security 02 — Referrer, we have given a simple example of How referrer can avoid basic attack. Actually, that sample is some kind of CSRF attack. Malicious website runs on 8889, and our blog system runs on 8888. There is an API in our blog system /api/transferPoints?dstUser=xxx. When called after authenticated, it will transfer points to dstUser xxx.

Below is the operations when user is not authenticated. It won’t cause any point loss.

But if a user is currently authenticated, points will be transferred after unconsciously click on the malicious link.

You can try this by checkout the 10CSRF branch, and run:

npm i
npm start
npm run-script startHack

3 How to avoid CSRF attack

  • Use only JSON APIs : AJAX calls use JavaScript and are CORS-restricted. There is no way for a simple <form> to send JSON, so by accepting only JSON, you eliminate the possibility of the above form.
  • Disable CORS : The first way to mitigate CSRF attacks is to disable cross-origin requests. If you’re going to allow CORS, only allow it on OPTIONS, HEAD, GET as they are not supposed to have side-effects. Unfortunately, this does not block the above request as it does not use JavaScript (so CORS is not applicable).
  • Check the referrer header : Unfortunately, checking the referrer header is a pain in the ass, but you could always block requests whose referrer headers are not from your site. This really isn’t worth the trouble. For example, you could not load sessions if the referrer header is not your server.
  • GET should not have side effects : Make sure that none of your GET requests change any relevant data in your database. This is a very novice mistake to make and makes your app susceptible to more than just CSRF attacks.
  • Avoid using POST : Because <form> s can only GET and POST, by using other methods like PUT, PATCH, and DELETE, an attacker has fewer methods to attack your site.
  • Don’t use method override! : Many applications use method-override to use PUT, PATCH, and DELETE requests over a regular form. This, however, converts requests that were previously invulnerable vulnerable! Don’t use method-override in your apps - just use AJAX!
  • Don’t support old browsers : Old browsers do not support CORS or security policies. By disabling support for older browsers (which more technologically-illiterate people use, who are more (easily) attacked), you minimize CSRF attack vectors.
  • CSRF Tokens : Alas, the final solution is using CSRF tokens. How do CSRF tokens work? 1) Server sends the client a token. 2) Client submits a form with the token. 3) The server rejects the request if the token is invalid. An attacker would have to somehow get the CSRF token from your site, and they would have to use JavaScript to do so. Thus, if your site does not support CORS, then there’s no way for the attacker to get the CSRF token, eliminating the threat. Make sure CSRF tokens can not be accessed with AJAX! Don’t create a /csrf route just to grab a token, and especially don't support CORS on that route!

Reference: Helmetjs, pillarjs

4 Sample of fix solutions

So there are many fix solutions:

1). Check change referrer : Web Security 02 — Referrer

2). Disable CORS : Web Security 11 — CORS

3). Change this API to post instead of using get, as this API will cause backend changes

4). CSRF Tokens

Now we will fix this problem in solution 3 and 4.

4.1 Change this API to post instead of using get

First let’s update our API from get to post. In backend indexPost.js , we change API from get to post (read from body instead of query ):

Also, we need to update UI as well (Ajax from get to post ):

Start the app again:

npm run-script startHack
npm run-script startPost

When we click the malicious get URL , nothing happens because this is a post request.

However, hackers can also update their methods. Let’s also have an example:

Malicious guys can work around this!

4.2 CSRF Tokens

The point of CSRF tokens is that, we will use another token to verify the user’s identity. And for each post request, which could do modification to our backend, we will check CSRF token and refresh it. Many people think it is not necessary to refresh them every time. But we won’t talk about that here. We will only give a simple example.

Now every time, if a user logged, we will put a CSRF token in the session, and we will stored it. When we use post method in UI, backend will verify the token in session and from post body. If verified OK, we will refresh this token. And if not, we will redirect user to login page.

Now in our indexCSRF.js , we add CRF related functions:

When we first logon, if everything is OK, we will set CSRF. When user calls transferPoints, we check CSRF:

What about UI? We should first store the token. staticFileSafeCSRF/index.html :

And when we do post, we should do more things staticFileSafeCSRF/post.js :

And now, start applications:

npm run-script startCSRF
npm run-script startHack

Yeah, even malicious post requests can’t success any more.

What is this place? Princess Margaret Bridge, Fredericton, NB, Canada.

--

--