Skip to content

[LiveComponent] CSRF token not valid after form second submit #2601

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

Open
tito10047 opened this issue Feb 24, 2025 · 9 comments
Open

[LiveComponent] CSRF token not valid after form second submit #2601

tito10047 opened this issue Feb 24, 2025 · 9 comments
Labels

Comments

@tito10047
Copy link

tito10047 commented Feb 24, 2025

Hi,
In my website https://6slov.sk/detail/aka-je-odpoved-na-zakladnu-otazku-zivota-vesmiru-a-vobec is on right side form, When you register and login to page, you can submit his.

When I submit form first time, everithing is ok, but when form return validation error (when you post more than 7 words) and submit form seconond time, then csrf protection failed.

Im I tried to simulate it on blank project, but not succesfull. I am at the end of my strength. I dont know what is wrong.

This is happend on every form in my site.

Can anybody help me investigate what is wrong?

Registration on my page is simple, only email is required. Site is on development, you can play with it.

@tito10047 tito10047 added the Bug Bug Fix label Feb 24, 2025
@smnandre
Copy link
Member

I'm wondering if you should add :prevent to your button too. It does trigger a submit right now, even when validation returns a 422.

This could solve the problem.

@tito10047
Copy link
Author

Yes, thats solve my problem.
Thaks :)

@tito10047
Copy link
Author

No, it doesn't :(

@tito10047 tito10047 reopened this Feb 24, 2025
@1ed
Copy link
Contributor

1ed commented Feb 24, 2025

I have the same issue and I can not reproduce it on a new project as well.

@1ed
Copy link
Contributor

1ed commented Feb 24, 2025

Actually I managed to create a reproducer: https://github.com/1ed/csrf-issue-encore
Maybe related to Symfony SameOriginCsrfTokenManager.php#L208

Maybe @nicolas-grekas could help here?

@1ed
Copy link
Contributor

1ed commented Feb 25, 2025

I tried the same example, without UX and it works normally.

@momocode-de
Copy link

I probably have the same problem, see #2682

When you submit the form for the second time, the following warning is logged:

CSRF validation failed: double-submit info was used in a previous request but is now missing.

The problem is this line: https://github.com/symfony/recipes/blob/main/symfony/stimulus-bundle/2.20/assets/controllers/csrf_protection_controller.js#L33

In the first submit, there is no attribute “data-csrf-protection-cookie-value” in the CSRF token input, which is why you enter the if and then the attribute is set and the CSRF token is written to the field.

In the second submit, the attribute “data-csrf-protection-cookie-value” exists, so that you cannot get into the if, no value is written to the input and therefore no CSRF token is transmitted with the request. This means that the CSRF token is only transmitted in the header and it is no longer a double-submit CSRF token.

I have created a workaround that solves the problem. I have written a csrf-fix_controller.js:

import { Controller } from '@hotwired/stimulus';
import { getComponent } from '@symfony/ux-live-component';

export default class extends Controller {
    async initialize() {
        this.component = await getComponent(this.element);

        this.component.on('render:finished', () => {
            const csrfField = this.element.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');

            if (!csrfField) {
                return;
            }

            csrfField.removeAttribute('data-csrf-protection-cookie-value');
            csrfField.value = 'csrf-token';
        });
    }
}

I then set this controller for my form component:

<div {{ attributes.defaults(stimulus_controller('csrf-fix')) }}>
    ...
</div>

The controller works by removing the “data-csrf-protection-cookie-value” attribute from the CSRF input and resetting the value every time my component is rendered. As a result, the CSRF token is set with each submit and passed with the request.

This is just a workaround that you can use in your projects. Ideally, however, this should be solved directly in the Symfony code, but I'm not deep enough into it to say how best to do this.

@momocode-de
Copy link

I think I have an idea how it could be solved in the Symfony code. I found out that if you take this line out of the if and execute it after the if, it will work. Because then the CSRF token is also transferred with the second submit.

Since the csrf_protection_controller is in the project and can therefore be edited as required, this would also be a workaround that anyone can quickly adopt.

@nicolas-grekas
Copy link
Member

If you found a fix that'd work for every use case, please submit a PR to update the recipe 🙏

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

No branches or pull requests

6 participants