I built CSRF protection in my application, by simply generating a random token on every page load, putting it into session, and then binding the token to the <body>
tag attribute like:
<body data-csrf-token="csrf_GeJf53caJD6Q5WzwAzfy">
Then on every form action or ajax request, I simply grab the token from the body tag and send it along.
This works great, except for a huge issue. Users are opening multiple tabs of the application, and I am seeing token collisions. For example, a user loads the first page and it generates a token, then they switch tabs, load another page, which generates a new token. Finally they switch back to the first page and submit a format action. This results in an invalid CSRF token error.
What is the best way to re-architect this to prevent collisions with multiple tabs, while keeping it as secure as possible.
Is simply generating a single token upon login the correct solution, instead of generating a new token on every page load?
Invalid or missing CSRF token This error message means that your browser couldn't create a secure cookie, or couldn't access that cookie to authorize your login. This can be caused by ad- or script-blocking plugins, but also by the browser itself if it's not allowed to set cookies.
CSRF tokens should be generated on the server-side. They can be generated once per user session or for each request. Per-request tokens are more secure than per-session tokens as the time range for an attacker to exploit the stolen tokens is minimal.
A "CSRF token mismatch" message will display on the Buy page if it has been idle for more than 15 minutes, indicating that your access token has already expired. To solve the issue, please try the following and purchase it again.
Assuming that your app is secured with SSL, then there is really no value created by generating new tokens on every page load. It doesn't stop an attacker who has exploited an XSS vulnerability – they'd have access to the freshly generated token anyway.
Remember what a CSRF token defends against: a malicious third-party page blindly trying to post data to your app in hopes that the user is logged in. In this kind of attack, the attacker would never have access to the CSRF token, so changing it frequently does no good.
Do not waste time and resources keeping track of multiple tokens per session. Just generate one at the start and be done.
You could use a single token upon login. As @Josh3736 points out, this works just fine.
If you really want to have one token per page, you could store an array of valid tokens in $_SESSION. You would then expire individual tokens as they are used. You could also optionally expire them after some timeout period, but that is only meaningful if the timeout is shorter than your session timeouts. But, again, what are you really accomplishing with this? A single token is perfectly fine for CSRF purposes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With