5
votes

Let's say that we use a CSRF token in our forms, but it happens that there is an unnoticed XSS hole on our site.

From what I uderstand, CSRF token protection is completely void in this case, because attacker can retreive it with XMLHttpRequest through XSS.

In such case, is there a way to enchant the CSRF protection in a way that it would survive the attack or should our site first have a secure anti-XSS protection before doing any king of CSRF at all?

Setting a new token upon every page request instead of token on login would deal with it? This brings up the problem of having more forms open at once and I don't like it.

2

2 Answers

4
votes

Your site should have closed any XSS holes that you've found otherwise CSRF is useless. However it would be useful to add CSRF in parallel so that once all XSS bugs are fixed the site's csrf protection is working too.

Unfortunately there is no way to protect against CSRF if there are XSS holes because with an XSS hole an attacker can read your website and check for tokens (using javascript). So any way and anywhere you add a token, that token can be found and then screenscraped

However if you make sure that there are no XSS bugs on your important pages and then add CSRF protection, there are still security holes but the skill level needed to chain multiple bugs together is more difficult.

2
votes

Short Answer: Origin header check is the only csrf protection mechanism which will hold it's ground even when there is XSS vulnerability.

These are the techniques that we use to prevent CSRF

Synchronizer Token

With the Synchronizer Token approach, the server embeds a dynamic hidden variable in an input form (Pay close attention, server has to have absolute control on the form generation so that it can generate a random string and embed in the form) and keep it in the session on server side --> verify on the form submit and invalidate it from the session as soon as it is used once. This will not work with Restful services powering a totally detached SPA(Single page applications) as Microservices has no access to the SPAs' form generation mechanism. When the form is submitted, the server can check and make sure that the hidden variable is present and that it is the correct value. See, this is being sent in the body (If we set this new token to cookie instead of form body, it defeats the whole thing, there will be no difference between this and sessionID).

If mybank.com is not sanitizing the form inputs (or in other words, if mybank.com is vulnerable to xss) hackers can overcome this csrf prevention method. https://rileykidd.com/2013/09/09/using-xss-to-csrf/

Double Submit Cookie

With the Double Submit Cookie approach, two cookies are sent back to the browser. One is the session id and the other is a random value (similar to the synchronizer token) Lets say sessionid and csrfid are those cookies.

There are 2 things to put this mechanism to work.

1) A feature built into the browser called the Same Origin Policy. This permits the script code to interact with other server endpoints only if those endpoints have the same origin (base URI) as the endpoint that delivered said script code. You might be wondering, “Whoa ! If one cookie isn’t secure on its own, how are two cookies going to be more secure?” Hang on, The key is in the next point

2) Having the second cookie (csrfid) included in subsequent requests in a custom header (let's say, X-XSRF-Token). It is up to your client script code to ensure that this is setup properly.

When you request the login page, two cookies are sent back by the server. The second cookie is used in a custom header for subsequent requests from the browser. The server checks for the existence of the custom header and checks the value against what was sent for that page.

Similar to the Synchronizer Token approach, an external site trying to spoof a page and trick you into submitting data to an active session, would fail as it would not be able to set the custom header for a site at a different URL.

Main actions

  1. Server have to generate a random value csrftoken cookie and send it to browser when the session is established.

  2. Client needs to access the cookie and set into custom header for every subsequent request

  3. Server needs to verify the CUSTOM HEADER (just ignore csrfid (or whatever name you gave) cookie. Since it's a cookie, it will be there with every request anyway, just ignore it )

This technique is effective because all browsers implement the same origin policy. Only code from the website on which cookies are set can read the cookies from that site and set custom headers on requests to that site.

Open questions (did not get a chance to test this out yet): What about the httpOnly on second (csrf-token) cookie.. do we need to set it or not? .. If we set it, will Javascript be able to access it to set to each subsequent request. On the other hand, if Javascript is able to access it, then together with un-sanitized-form-negligence XSS vulnerability, XSS attack can expose the user's csrf-token. Then, if evil-guy is be able to fool users into visiting evil-site-which-has-a-csrf-form.com while having an active session in mybank.com, csrf attack can take place. Agreed, there are too many "if"s for the attack to take place, but still it's not secure.

By far, these methods are not that effective if there is XSS vulnerability. Let's take a look at the 3rd option

Origin header check

All browsers, including Internet Explorer 9 and later, send an Origin header in their requests. This header is not allowed to be set by Javascript, which gives you a high degree of confidence that the browser has the right information in that header. The server can then explicitly check that header and verify that the base URI matches the server’s. If the server is set to reject browser requests where the base URI in the Origin header does not match the expected value, then a third-party site trying to spoof the look of your page would be foiled as the Origin set in the browser would be different than what was expected.

This will not fail even if mybank.com has a XSS vulnerability. Catch Nada! If your users are using (very) older versions of browsers you might have other problems to solve anyway :)

Reference: https://stormpath.com/blog/secure-single-page-app-problem