Jump to content

Does $session->CSRF only change when PHP session ID does?


DrQuincy
 Share

Recommended Posts

I use PW's in-built CSRF for forms. So I add a hidden tag:

<input type="hidden" name="<?= $session()->CSRF->getTokenName() ?>" value="<?= $session()->CSRF->getTokenValue() ?>" />

And then when the form is sent I check:

try {

    $session->CSRF->validate();

} catch (\Exception $e) {

    // ...

}

It has always worked for me. I have a client saying that they got a CSRF error when they filled a form out (payment form; quite lengthy but can't imagine it taking more than five minutes). This person is not very technical so it is hard to get information out of them but I can only conclude they either took ages filling the form out or they were signed into the CMS and logged out after loading the form (the latter has happened to me before).

My questions are:

  1. What causes the $session()->CSRF token to change? Is it directly tied to session_id() or can a change occur (assuming no manual regeneration in my code) without the session ID changing?
  2. Do you think it is advisable on longer forms that use CSRF to have a background AJAX call that runs a simple PHP script every few minutes that simply has session_start() in it (rather than create a more resource-heavy PW request) to keep the session alive?

Thanks.

Link to comment
Share on other sites

Token is stored in session data and thus indeed automatically invalidated if session expires. It can also be invalidated if another CSRF check runs meanwhile (but only if that check specifically requests that the token be regenerated, which is not the case with most core features), so technically user doing something else on the site that triggers a CSRF check could result in such an issue. (It's possible to provide an ID argument for getTokenName(), validate(), etc. which may help with this, although it is likely quite a rare occurrence.)

In my experience an issue like this would most commonly be a result of something in the user's environment changing, i.e. IP or some other value used for session fingerprinting has changed and thus session gets invalidated. This behaviour can be tweaked via the $config->sessionFingerprint setting.

In my opinion a background process is rarely needed / useful. I wouldn't bother with it, unless this is a critical feature that definitely should never cause errors and where users are likely to spend loads of time. Also: session_start() would not remove the fingerprint issue, so this will likely have limited applicability. You could probably build a setup where the token is checked and/or regenerated periodically, but this is most likely overengineering.

By the way: you can use echo $session->CSRF->renderInput() and use if ($session->CSRF->hasValidToken()) { ... } instead of custom markup and try-catch. Not a big deal, they just make things sightly more convenient 🙂

  • Like 2
Link to comment
Share on other sites

Many thanks for the detailed reply. 🙂

28 minutes ago, teppo said:

It can also be invalidated if another CSRF check runs meanwhile, so technically user doing something else on the site that triggers a CSRF check could result in such an issue.

Could this include simply saving a page in the CMS? How and why does this happen? It was my understanding CSRF tokens were basically just a random string tied to the session and so long as the value in the form and the value session match all is okay. If I understand what you're saying correctly this could get in the way and cause false negatives. I don't see why two legitimate requests couldn't happen concurrently. Is there any way to disable this?

30 minutes ago, teppo said:

In my experience an issue like this would most commonly be a result of something in the user's environment changing, i.e. IP or some other value used for session fingerprinting has changed and thus session gets invalidated. This behaviour can be tweaked via the $config->sessionFingerprint setting.

I always have $config->sessionFingerprint = false in config.php because one of my colleague's IP changes all the time (several times a day) and kept getting logged out of the CMS. Does the CSRF token always become invalid on a IP change? If so, again this could be problematic. If an IP change does not affect this with $config->sessionFingerprint = false then it can't be this since, as I say, I always switch it off.

I do wonder if it is to do with him having the front-end and back-end open at the same time.

Thanks!

Link to comment
Share on other sites

19 hours ago, DrQuincy said:

Could this include simply saving a page in the CMS? How and why does this happen? It was my understanding CSRF tokens were basically just a random string tied to the session and so long as the value in the form and the value session match all is okay. If I understand what you're saying correctly this could get in the way and cause false negatives. I don't see why two legitimate requests couldn't happen concurrently. Is there any way to disable this?

Sorry, my post was vague on this part (updated now): CSRF token is only reset if/when a reset was specifically requested while validating the token. Page save won't do this, but a custom CSRF check could do it.

Only core feature (that I'm aware of) that resets the token is logging in... which is unlikely to occur multiple times during single browsing session 🙂

  • Like 1
Link to comment
Share on other sites

Ah right, thanks for the clarification. 🙂

Quote

CSRF token is only reset if/when a reset was specifically requested while validating the token. Page save won't do this, but a custom CSRF check could do it.

Just to be clear though, simply calling $session->CSRF->validate() will not reset the token, will it? That's all I'm doing, which I guess is a custom CSRF check.

Thanks!

Link to comment
Share on other sites

22 minutes ago, DrQuincy said:

Just to be clear though, simply calling $session->CSRF->validate() will not reset the token, will it? That's all I'm doing, which I guess is a custom CSRF check.

No, not under normal circumstances it won't.

$session->CSRF->validate() will only ever reset the token in case an invalid token was provided, or if the token was initially created as a single use token (via $session->CSRF->getSingleUseToken()).

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...