It seems to me that the primary goal of CSRF is to confirm that the client making the request is the client we expect.
The solution I've commonly seen is:
- Server generates random CSRF Token
- Server sets CSRF token in cookie
- Server injects the CSRF token into the form when generating the form OR
- Server passes the CSRF token to javascript and javascript injects the CSRF token as a header on XMLHTTPRequests
- When a request is received, it's validated by checking that the CSRF token in the cookie matches the CSRF token in header/form value.
It makes a lot of sense to me that the server is generating the CSRF for (3)(1), but I cannot come up with a reason why it's necessary for (3)(2).
Instead, if the client is pure javascript, I believe this is safe:
- Javascript generates a random CSRF token
- Javascript sets the CSRF token in a cookie
- Javascript passes the CSRF token in the header when making an XMLHTTPRequest
- Server checks that CSRF token in the header and cookie match
My understanding is that 3 and 4 are both things an attacker cannot do, so this would also sufficiently block attacks. Is that correct?
If that is safe, do we even need to do step (1) and (2)? Would this be safe as well because of same-origin policy (assuming cors is configured properly)?
- Javascript sets an 'CSRF-Safe: true' header in XMLHTTPRequest
- Server checks that the header CSRF-Safe exists and is set to "true"