I have mitigated cross-site scripting in my code by input validation, whitelisting characters (HTML tags too), and using X-XSS protection headers. Will the fixes I have implemented for mitigating XSS mitigate CSRF attack in my application?
In a CSRF attack the attacker from site A can use the browser of user U as a trampoline to trigger an authenticated request against site against site B, provided that user U is already authenticated against site B and B has no CSRF protection.
One example would be to include an image on site A like this:
When including the image a request will be sent against site B which includes existing cookies and basic authentication information the user U has inside the browser for site B. Thus the request looks authenticated and site B will execute if no CSRF protection is in place. Thus all what is needed for the attack is that user U visits site A, either knowingly because the attacker might embed such a link into a public forum site, or unknowingly because such link is embedded into an advertisement. And since this is an image no action need to be done by the user and he will probably not even realize that something bad happened, like in How millions of DSL modems were hacked in Brazil, to pay for Rio prostitutes.
Given the above example it should be clear that no XSS is needed to execute a CSRF and that neither TLS nor protection of the session cookie against tampering will help against CSRF.
I wanted to add an addendum to @steffenullrich's (totally correct) answer: just because his example uses a GET request for the CSRF (because that's the easiest to demonstrate), simply making all state-changing requests only usable via POST does NOT protect against CSRF. An attacker can still forge a POST request pretty easily. A few ways to do this:
- Create an HTML
<form>that POSTs to the vulnerable site when submitted, fill it with pre-populated
<iframe>on a site you (the attacker) control. The victim visits your site, the iframe loads, the JS submits the form as a POST request to the vulnerable site, the victim's browser sends along the cookies,
Authorizationheader, and/or any automatic other method of authentication (IPSec, TLS client cert, simple IP address check, whatever), the server takes the requested action, and the victim doesn't even see because nothing appears to happen on the main page.
Access-Control-Allow-Originor other CORS response headers back to the victim's client, the request will still be processed by the server (and Fetch allows optionally sending requests blindly without using CORS, as if just sent via a Form submission).
HTTP verbs other than the common ones (GET, POST, and to a lesser extent HEAD and OPTIONS) are more secure; HTML forms aren't allowed to use those methods, and CORS requests using them need to pass a "preflight" check where the client queries the server before sending the actual request, and won't send it at all if the server doesn't respond appropriately. However, the best protection against CSRF is to have a secret value (attached or related to, but different from, your session token) that is included on valid HTML forms (and therefore in non-forged requests from those forms) but is different for every user session so that the attacker can't predict what the victim's anti-CSRF token would be. If this token is missing or not correct for the submitting user's session, assume it's a CSRF attack and ignore the requested action.