Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSRF token mismatch full cache strategy #10801

Open
danielreales7 opened this issue Sep 14, 2024 · 15 comments
Open

CSRF token mismatch full cache strategy #10801

danielreales7 opened this issue Sep 14, 2024 · 15 comments

Comments

@danielreales7
Copy link

Bug description

If I don't use the full cache strategy on my site, the forms work fine. The problem comes when they are used. If I try to send the form, I get the following: CSRF token mismatch.

It seems that the token is not being updated behind the scenes.

I tried wrapping the form with a {{ nocache }} and it was fixed.

Then I realized that if I send the form in Spanish without filling in the inputs, I get the error messages in Spanish. So far so good. If I go to the English site and send it, it shows me the messages in English. Also good. But if I go back to Spanish, it shows me the English messages.

According to the documentation, if full cache is used, we must use {{ nocache }} https://statamic.dev/static-caching#csrf-tokens

Same here: https://statamic.dev/forms#caching

How to reproduce

Enabling the full cache strategy and multisite.

Logs

No response

Environment

Laravel Version: 11.16.0
PHP Version: 8.2.20
Composer Version: 2.7.9
Environment: production
Debug Mode: OFF
Maintenance Mode: OFF
Timezone: UTC
Locale: es

Cache
Config: CACHED
Events: NOT CACHED
Routes: CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: file
Database: sqlite
Logs: stack / single
Mail: smtp
Queue: sync
Session: file

Statamic
Addons: 5
Sites: 2
Stache Watcher: Disabled (auto)
Static Caching: full
Version: 5.16.0 PRO

Statamic Addons
spatie/statamic-responsive-images: 5.0.0
studio1902/statamic-peak-browser-appearance: 3.5.0
studio1902/statamic-peak-commands: 8.4.0
studio1902/statamic-peak-seo: 8.15.3
studio1902/statamic-peak-tools: 6.3.0

Installation

Starter Kit using via CLI

Additional details

No response

@danielreales7
Copy link
Author

The problem also occurs when doing the opposite with the application languages. If I access English first and then Spanish and go back to English, it returns the messages in Spanish.

It depends on the first page I cache. I've been debugging and it comes from this function in src/Http/Requests/FrontendFormRequest.php:

public function validateResolved()
    {
        // If this was submitted from a front-end form, we want to use the appropriate language
        // for the translation messages. If there's no previous url, it was likely submitted
        // directly in a headless format. In that case, we'll just use the default lang.
        $site = ($previousUrl = session()->previousUrl()) ? Site::findByUrl($previousUrl) : null;

        return $this->withLocale($site?->lang(), fn () => parent::validateResolved());
    }

@duncanmcclean
Copy link
Member

You shouldn't need to wrap the form in the {{ nocache }} tag. CSRF tokens should be automatically replaced when using full-measure caching.

Are you using the native {{ form }} tag? Are there any console errors when viewing a cached page?

@danielreales7
Copy link
Author

You shouldn't need to wrap the form in the {{ nocache }} tag. CSRF tokens should be automatically replaced when using full-measure caching.

Are you using the native {{ form }} tag? Are there any console errors when viewing a cached page?

Now I was testing locally and I am not getting the CSRF mismatch error. I was watching production. I'll see if the token expires and try again to show you the error.

But it keeps happening that when a page is cached, whether it is English or Spanish, and I submit a form, I get error messages for the wrong language.

@duncanmcclean
Copy link
Member

duncanmcclean commented Sep 16, 2024

But it keeps happening that when a page is cached, whether it is English or Spanish, and I submit a form, I get error messages for the wrong language.

That's with the {{ nocache }} removed, yeah?

How are you submitting the forms? With an AJAX request or just a normal <form> submit?

@danielreales7
Copy link
Author

But it keeps happening that when a page is cached, whether it is English or Spanish, and I submit a form, I get error messages for the wrong language.

That's with the {{ nocache }} removed, yeah?

Yes, exactly.

If I access the English form without having any page cached, I get the error messages in English. If I go to Spanish and submit the form, I get the error messages in Spanish. Now once both are cached, if I go back to the English form, I get the Spanish messages. The same thing happens in a different order.

@danielreales7
Copy link
Author

danielreales7 commented Sep 16, 2024

Look now:

image

I have deleted the browser cookies. Now both pages are cached. If I try to submit the form again I get what I told you above.

This happens both with and without the {{ nocache }} tag.

@duncanmcclean
Copy link
Member

How are you submitting the form? Are you using AJAX?

@danielreales7
Copy link
Author

I'm using precognition. It's the peak studio component but I've extracted the form submission to a dedicated js file.

This is my sending.js:

 export default () => ({
    success: false,
    submitted: false,
    form: null,
    init() {
        this.form = this.$form(
            'post',
            this.$refs.form.getAttribute('action'),
            JSON.parse(this.$refs.form.getAttribute('x-data')).form,
            {
                headers: {
                    'X-CSRF-Token': {
                        toString: () => this.$refs.form.querySelector('[name="_token"]').value,
                    }
                }
            }
        )
    },
    submit() {
        this.submitted = true
        this.form.submit()
            .then(response => {
                this.form.reset()
                this.$refs.form.reset()
                this.success = true
                this.submitted = false
                setTimeout(() => {
                    this.success = false
                }, 4500)
            })
            .then(this.$refs.form.scrollIntoView())
            .catch(error => {
                const summary = document.querySelector('#summary')
                if (summary) {
                    this.$focus.focus(summary.querySelector('a'))
                }
                else {
                    console.log(error)
                }
            })
    }
 });

image

@jasonvarga
Copy link
Member

When you visit one of your cached form pages, do you see an AJAX request to /!/nocache being done automatically?

@danielreales7
Copy link
Author

When you visit one of your cached form pages, do you see an AJAX request to /!/nocache being done automatically?

If I load a page cached, I can see: /!/nocache with status 200

When send the form to: /!/forms/contact 419 unknown status

@danielreales7
Copy link
Author

@duncanmcclean I create a new project if you need test error: https://github.com/danielreales7/test-cache-form

I did a clean installation of Statamic 5 (with Peak Studio) without any configuration. If you try to send the form with all the fields empty, it shows the error messages correctly.

If you now add STATAMIC_STATIC_CACHING_STRATEGY=full to the .env, you cache the page, once cached, try to delete cookies from the browser and try to send the form.

You will see in the console:

image

@danielreales7
Copy link
Author

Grabacion.de.pantalla.2024-10-02.a.las.22.00.51.mov

I am attaching a video of something I just realized. If it is sent without being cached, it shows the errors. When it is cached and I delete cookies, it does not show the errors. However, if I write on any input and send the form again, it shows the errors again.

@robdekort
Copy link
Contributor

It seems when a page is cached and you submit an empty form you get a token mismatch error. As soon as you start filling in fields stuff kicks back in.

@ryanmitchell
Copy link
Contributor

Is it possible you're submitting before the nocache JS has run and replaced the csrf token in the form?

@danielreales7
Copy link
Author

No. Nocache is loaded before submitting the form. If I don't use cache it works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants