Server keeps track of which CSRF token is given to which client using cookies (usually some form of SessionID), and stores it on the server somewhere.
It is a very common pattern and all frameworks support it with the concept of "sessions" on the back end.
you don't need to store anything on the server. cookies for that domain are sent with the request and it is enough for the server to check its cookie with the csrf request data.
browsers would send the bank.com cookies with the bank.com request. It is security built into the browser which is why its so important to use secure browsers and secure cookies.
If the malicious user convinces the user to use an insecure browser you can circumvent CSRF, but at that point there are probably other exploits you can do.
You can validate the CSRF is valid by keeping a key on your server and matching that the token you get can be derived from that key.
See Django's implementation of CSRF for more details. CSRF tokens are separate from session and no CSRF information needs to be stored in database to validate CSRF.
depending on why you'are asking the question, * because it decrypts correctly * because it contains some user identifier
People don't usually store sessions in cookies because cookies can't be very big, and session do become big. So what people do instead they store cookies in databases, and put session identifiers into cookies.
CSRF token can be entirely separate from sessions.
so evil.com will now require some sort of authentication mechanism with bank.com to scrape a valid CSRF token. If this authentication works (either if the user willingly gave their login information to evil.com, or they have a deal with bank.com directly), then there's no issues, and it works as expected.
A form on evil.com posted to bank.com does send your cookies by default.
But not for fetch() in the browser. And certainly not for a request made from evil.com's server.
Also, bank.com would want to create CSRF tokens tied to current user. Or ensure its CORS protections never allow cross-origin requests (the default) if it were to use generic CSRF tokens.
Or just use same-origin cookies.
Or don't even use cookies at all.
What stops evil.com from having an API endpoint called evil.com/returnBankCSRFToken that goes to bank.com, scrapes token and returns it?
CSRF tokens are just part of an html form - they are not hidden or obscured and thus scraping them is trivial.
When I go to evil.com, it calls the endpoint, gets token and sends a request to bank.com using said token, thus bypassing CSRF?