phpsecuritycsrfcsrf-protection

CSRF token collisions with multiple tabs


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?


Solution

  • 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.