I've come across several other questions about CSRF, but none seem to answer my question. It feels like there's something I'm missing in regards to how CSRF works.
Please read the entire post before answering.
I've been reading up on Cross-Site Request Forgery and the various tactics used to mitigate and prevent it (and yes I do know that you should use a many as possible).
However the primary one that gets mentioned is to use a Nonce/One Time Key embedded in the web page as a hidden form parameter, so this is what I'm focusing on.
To be clear, I do understand what the Nonce is attempting to do, but it also seems just stupidly easy to defeat. Surely if the attacker is able to send a POST request to another site, they can also do a GET request, scrape the token from the page, and just include it in their request?
I've tried to come up with a way to see how it would be useful, but I really just don't see how it helps in practice.
To be clear, I'm not trying to say that I know better. Again though, unless I'm missing something about CSRF, this seems like a valid attack, and I don't see it addressed on any site that gives guidelines for preventing CSRF attacks.
Please, let me know where I'm wrong.
Thanks!
CSRF is about a remote attacker exploiting a session that a user has with a website.
First, a lame example. You make a session with your bank (log in). While logged in, attacker gets you to visit his malicious website. On the malicious website, you click an awesome link to see something you really want. However, the malicious website posts to an url the right data to transfer money to the attacker. You did not want to do that, and the website you were using had seemingly nothing to do with your bank. Still the bank website got a request from you to transfer money to the attacker. This works, because you already had a session with your bank, your session id was stored in a cookie, and cookies get sent based on the target url, regardless of where the user clicks (see below). This is kind of the base case of csrf.
So if the attacker gets you to visit his malicious site, why can't his javascript just download the banking page first, and get the csrf token as you proposed?
Well, why can't he just read your banking details, account number, your balance? For the same reason, the same origin policy (SOP) of web browsers. If the malicious javascript on the attacker's website makes a request to the bank url, the origin of the request is different from its destination. Contrary to common belief, the request will still be made, the bank server will receive and process it, and send a response. However, your browser will not allow the calling javascript access to the response from a different origin (unless CORS headers are sent, but that's a somewhat different, though related topic).
So the attacker on his malicious website has no way to get access to a page downloaded by the victim user from a different origin, and this prevents the attack you were describing. The attacker can of course go ahead and download the bank page himself, but the csrf token will of course be different in his own session with the bank. But he cannot get the token in a victim user's session.
In other words, the csrf token generated in a page and "remembered" on the server allows the server to check that the request is coming from a page that was actually generated by the server. This token cannot be accessed by other websites via cross-domain requests due to the SOP.
Note that the statement above that cookies get sent regardless of the request origin is not necessarily true though. The new-ish SameSite attribute of cookies allow some control over which cookies should be sent where, and this attribute might effectively mitigate CSRF in compliant browsers, with some UX implications.
Also note that an XSS vulnerability would indeed allow an attacker to read the CSRF token - or any other data in a page for that matter. Hence XSS is generally considered a higher severity flaw than csrf.