All add-ons currently require PHP 7.4 or greater.

On July 4th 2024 PHP 8.2 will be the new minimum requirement for all add-ons. Expect any add-on released after that date to require 8.2 or greater. Some releases may not immediately take advantage of 8.x specific features in PHP, which means you might, be able to continue using new releases in PHP 7.4, however, if you experience an error the first thing you should do is update to PHP 8.2 then create a support ticket if the error persists.

Publisher does not support the Fluid field type. Please do not contact asking when support will be available.

If you purchased an add-on from expressionengine.com, be sure to visit boldminded.com/claim to add the license to your account here on boldminded.com.

Ticket: CSRF token issue

Status Resolved
Add-on / Version Speedy 1.8.1
Severity
EE Version 7.3.14

chrisdaviesweb

Jan 04, 2024

Hi Brian,

I am using Speedy with static caching.
When logged out of the system, the CSRF token set works correctly. If I then log in as super admin, all forms return the ‘This form has expired. Please refresh and try again.’ error.
The same CSRF token is set for both logged out and logged in - I see this on the forms, as well as the cookie set.

#1

chrisdaviesweb

Comment has been marked private.

#2

BoldMinded (Brian)

I think this is an issue with logging into the site in the same browser window. I re-created this locally and when using 2 different private windows it does update the token correctly in each window, but since it’s all based off of the cookie, your cookie hasn’t changed after you login to the CP in the same window. Have you tried this pattern without Speedy? Even on my site here, which runs EE, I’ve had issues with the form telling me it’s expired after I login to the CP vs logging in through the front-end of the support section. So I’m not sure there is something inherently wrong with Speedy, but more of an issue of how EE handles the forms and CSRF tokens via cookies.

#3

chrisdaviesweb

Hi Brian, Thanks for coming back to me. I’ve run a few tests. On the dev version, which has Speedy setup, I’m noticing that there are two ‘exp_csrf_token’ cookies. One with the domain with a leading ‘.’, the other without. If I disable Speedy, only one cookie is created/updated. With Speedy enabled, if I log in via the front-end, one of these cookies has it’s value updated, but whilst logged in, neither work (I moved the token from one to the other to check). On the live site, where Speedy has never been setup, only one cookie is ever created, with the token updated when I log in via back-end or front-end. I’m not able to replicate any issues with the CSRF when Speedy is not enabled or setup.

#4

BoldMinded (Brian)

Have you changed any of EE’s cookie settings? Prefix, TTL, or anything? I also can’t tell what the domain name is for the site… is it on a sub-domain? Locally I only have a single cookie created, I don’t see a second one like you do.

#5

chrisdaviesweb

Comment has been marked private.

#6

BoldMinded (Brian)

What do you mean “The domain is set as ‘.lightandland.test’ under cookie settings”? Can you share a screenshot?

#7

BoldMinded (Brian)

Oh, I see what you’re saying now. Try not entering a value into the Domain field, just let EE use it’s defaults.

#8

BoldMinded (Brian)

Part of what the issue might be, is that Speedy has to create the cookies with PHP’s setcookie() function, and can’t utilize EE’s ee()->input->set_cookie() because the whole point of static cache is to not boot up EE. EE’s set_cookie function does a lot of work, which would be impossible to re-create without using EE.

#9

chrisdaviesweb

I’ve removed the domain field and it looks like only the one CSRF cookie is now being created. When logging in via the front end, the CSRF token is updated, but the forms then still return the same error.

#10

BoldMinded (Brian)

Is this a rare edge case where someone would need to fill out that form and login to the CP?

#11

chrisdaviesweb

CP perhaps, but log in via the front-end, no. Lots of users may use the forms, before either registering or loggin in.

#12

BoldMinded (Brian)

In the video you mention logging in as Super Admin… are you logging into the CP and then coming back to the front-end or logging into the front-end as a Super Admin? Have you tried this with a normal non-admin account?

#13

chrisdaviesweb

Just tried this and unfortunately its the same.

#14

BoldMinded (Brian)

I see the issue. Once logging in it uses the database to store the session id, which is different than the cookie that Speedy generates. I’m not exactly sure how to resolve this, and it make take awhile. If you’d like a refund I’ll be happy to do that, otherwise you’ll have to wait until I can hopefully resolve this, but I have no idea when that would be.

#15

BoldMinded (Brian)

Or this could be a use case to ignore the page(s) with forms on them from getting cached in the first place, or load the forms in via Ajax. https://docs.boldminded.com/speedy/docs/static-caching/real-world-example

#16

chrisdaviesweb

Thanks, Brian. I’d really like to have Speedy working for this client, so I’m hoping I can figure a solution, along with the global vars issue I will post. If I can’t, then a refund would be appreciated. For this issue, I feel like the solution I’ve come up with is almost too simple… Can you think of any issues with the following? So, I’ve created a very basic plugin, which if logged in, grabs the users session_id, queries this in the ‘exp_security_hashes’ table to retrieve the current CSRF, then returns it. I output this in a new template, which isn’t cached with Speedy. Using AJAX, I fetch this template and update all ‘csrf_token’ inputs. In my initial testing, this works. This seems a far better option than loading in all the complete forms via AJAX. My thoughts are, this could be set to target only those forms that are on pages which are cached, simply by adding an class to those forms. If the user isn’t logged in, then the plugin doesn’t run.

#17

BoldMinded (Brian)

Your solution might work, but it’s also similar to the path that I’m pursuing to fix the issue in Speedy itself. It needs to make a connection to the DB and fetch that hash like you mentioned, but I just have to do it with a raw PDO query instead of EE’s built in ORM, which isn’t instantiated b/c EE isn’t booted. It’ll take a couple hours but I think it’ll work, just not sure when I’ll get to those couple hours of work… hopefully sometime next week.

#18

chrisdaviesweb

Your solution sounds perfect. If you think you’ll find the time to look at this in the next week or so, I’ll hang tight.

#19

BoldMinded (Brian)

Comment has been marked private.

#20

chrisdaviesweb

Hi Brian, Just tested with this and CSRF doesn’t work, when moving from logged in to logged out, or logged out to logged in. Same as before.

#21

BoldMinded (Brian)

Comment has been marked private.

#22

chrisdaviesweb

Comment has been marked private.

#23

BoldMinded (Brian)

Not sure what we’re doing differently, but here are a few screenshots of what I’m seeing:

Uncached first visit to the page not logged into the CP, as expected it is setting a token that matches my cookie, and this token is actually what is saved to the cache:

Reloading the page, thus getting the cached version, still not logged into the CP it’s updating correctly, but happens to be the same token value b/c it’s still the same user:

Visiting an uncached copy of the page at a different url for the first time, same user, it shows the same token, which is correct:

New private window, new user, loading the 2nd page which is cached, and it’s updating the token with the new user’s token:

and finally this is after I logged into the CP in the 2nd private window, and it’s switching to a new token that matches the session_id from the database.

#24

chrisdaviesweb

Thanks for the reply, Brian. I’ve cleared everything instead using ‘Clear Driver > Static’ instead of ‘Clear All Cache’ and haven’t been able to replicate this issue again… In tests since, the ‘csrf_token’ field isn’t wrapped in your <!— CSRF_TOKEN_UPDATED—> comment - Is this correct? I had been using that as an indication that it was definetly loading the cached version.

#25

chrisdaviesweb

Just had another occurance of the <!— CSRF_TOKEN_UPDATED—> wrapped field and it’s failing to submit. Newly cached item, so not sure what’s going.

#26

chrisdaviesweb

Looking at the cached file, the CSRF token is correct. If I take it from there and place it into the token field, the form submits - so is it that the swapped out contents is the cause, hence the comment outputting?

#27

BoldMinded (Brian)

Are you logged in our logged out? In Security & Privacy what are your settings?

#28

chrisdaviesweb

Comment has been marked private.

#29

chrisdaviesweb

Comment has been marked private.

#30

chrisdaviesweb

Comment has been marked private.

#31

BoldMinded (Brian)

The UPDATED comment will not show for uncached pages. The first person to load a page, thus creating the cache for it, will have their token in the cache, but all subsequent page loads should be from cache and then the UPDATED comment is inserted and the token is updated to the user who is viewing the cached page.

#32

BoldMinded (Brian)

For shits and giggles, create a new blank template and use just the content form from the docs like I am and see if you can get it to submit using the same logged in/logged out scenarios, and obviously statically cache that template. I want to see if you can get the same behavior using that form… just to rule things.

https://docs.expressionengine.com/latest/add-ons/email.html#email-contact-form

#33

BoldMinded (Brian)

Comment has been marked private.

#34

chrisdaviesweb

Comment has been marked private.

#35

BoldMinded (Brian)

Have you been re-generating the cache utility files after each build I’ve been sending? Make sure you delete the static/utilities folder and re-generate the files from the Speedy admin page. The changes I’ve been making require those files to be updated.

#36

BoldMinded (Brian)

https://docs.boldminded.com/speedy/docs/control-panel#static-cache-configuration

#37

chrisdaviesweb

Comment has been marked private.

#38

BoldMinded (Brian)

Have you checked your php log files or turned up EE’s error reporting? I’ve been testing with Redis as my driver not static files, and when I switched to static files I got this error, just want to know if you’re getting the same thing.

Warning: Undefined property: Speedy_e7481f1b0bdf29ba9f0fee44611c1cac::$options in /default_site/static/speedy/csrf-test/index.php on line 31

#39

chrisdaviesweb

Comment has been marked private.

#40

BoldMinded (Brian)

Comment has been marked private.

#41

chrisdaviesweb

Comment has been marked private.

#42

BoldMinded (Brian)

Comment has been marked private.

#43

chrisdaviesweb

Thanks, Brian. On first glance, all seems to be working! I’ll do some proper testing on everything as soon as I have time.

#44

BoldMinded (Brian)

Yay, we got there! Thanks for the detailed videos, it helped a lot. I’m going to go ahead and close this ticket, but feel free to re-open if you need to.

Login to reply