The common way to prevent CSRF requests: Each time the user loads a page that contains a form to be POSTed, the user is issued a CSRF token that it supposed to be unknown to potentially malicious third-party sites. The token is issued both as a cookie and as a hidden
<form> field. The client is supposed to authenticate each POST request by putting a valid CSRF token in the request's body and by presenting a valid cookie.
Let's say the user is logged in to
example.com and, on another tab, browses to
evil.com wants to attack
example.com/form.html. I understand that
evil.com can issue a POST request to a
example.com/form.html and this site will interpret this malicious POST request as a valid request coming from the user. CSRF tokens prevent this scenario, because they are supposed to be unknown to
evil.com; it cannot send the correct token with its maliocious POST request, so the
example.com server will reject that request.
And here comes the part I fail to understand. The CSRF token is issued both as a cookie and as a hidden form field. For the cookie part, this is trivial: IIUC every request to
example.com automatically contains all cookies that come from
example.com; so, assuming that on another tab the user is logged in to
example.com, the malicious POST request will contain the valid CSRF cookie. Is this correct?
For the hidden form field part, this get slightly more complicated, but not much.
Evil.com can issue a GET XMLHttpRequest to
example.com/form.html and that request will succeed, because the user is logged in to this site on another tab and because GET requests aren't protected by CSRF. In response,
example.com/form.html HTML source, which contains the
<form> in question, which in turn contains the hidden
<input> field with the CSRF token.
Evil.com can now parse the received document, extract the token and bundle it with its subsequent malicious POST request to
example.com/form.html, theferore succesfully completing a CSRF attack.
What is wrong in my above reasoning? What am I failing to understand?