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

Cake 4.0.5 to 4.0.6 upgrade: Missing CSRF token body Cake\Http\Exception\InvalidCsrfTokenException #14471

Closed
1 of 3 tasks
cnizzardini opened this issue Apr 19, 2020 · 22 comments
Closed
1 of 3 tasks
Labels
Milestone

Comments

@cnizzardini
Copy link
Contributor

This is a (multiple allowed):

  • bug

  • enhancement

  • feature-discussion (RFC)

  • CakePHP Version: 4.0.6

  • Platform and Target: Ubuntu 18 LTS, Apache, PHP 7.2 FPM

What you did

  1. Upgrade to 4.0.5 from 4.0.6
  2. Went to do login in on my website
  3. Encountered Missing CSRF token body Cake\Http\Exception\InvalidCsrfTokenException

What happened

This happens on any form submission. A workaround is clearing cookie, but iis it reasonable to force clearing this data on each release to avoid any potential CSRF errors? I have locked my CakePHP version to 4.0.5 for now.

Stack Trace:

Missing CSRF token body
Cake\Http\Exception\InvalidCsrfTokenException
Toggle Vendor Stack Frames
CORE/src/Http/Middleware/CsrfProtectionMiddleware.php:254
Cake\Http\Middleware\CsrfProtectionMiddleware->_validateToken
CORE/src/Http/Middleware/CsrfProtectionMiddleware.php:133
Cake\Http\Middleware\CsrfProtectionMiddleware->process
CORE/src/Http/Runner.php:73
Cake\Http\Runner->handle
CORE/src/Http/Runner.php:58
Cake\Http\Runner->run
CORE/src/Routing/Middleware/RoutingMiddleware.php:162
Cake\Routing\Middleware\RoutingMiddleware->process
CORE/src/Http/Runner.php:73
Cake\Http\Runner->handle
CORE/src/Routing/Middleware/AssetMiddleware.php:68
Cake\Routing\Middleware\AssetMiddleware->process
CORE/src/Http/Runner.php:73
Cake\Http\Runner->handle
CORE/src/Http/Middleware/DoublePassDecoratorMiddleware.php:74
Cake\Http\Middleware\DoublePassDecoratorMiddleware->Cake\Http\Middleware\{closure}
ROOT/vendor/dereuromark/cakephp-setup/src/Middleware/MaintenanceMiddleware.php:48
Setup\Middleware\MaintenanceMiddleware->__invoke
CORE/src/Http/Middleware/DoublePassDecoratorMiddleware.php:75
Cake\Http\Middleware\DoublePassDecoratorMiddleware->process
CORE/src/Http/Runner.php:73
Cake\Http\Runner->handle
CORE/src/Error/Middleware/ErrorHandlerMiddleware.php:119
Cake\Error\Middleware\ErrorHandlerMiddleware->process
CORE/src/Http/Runner.php:73
Cake\Http\Runner->handle
CORE/src/Http/Middleware/CspMiddleware.php:67
Cake\Http\Middleware\CspMiddleware->process
CORE/src/Http/Runner.php:73
Cake\Http\Runner->handle
CORE/src/Http/Middleware/SecurityHeadersMiddleware.php:257
Cake\Http\Middleware\SecurityHeadersMiddleware->process
CORE/src/Http/Runner.php:73
Cake\Http\Runner->handle
ROOT/vendor/cakephp/debug_kit/src/Middleware/DebugKitMiddleware.php:60
DebugKit\Middleware\DebugKitMiddleware->process
CORE/src/Http/Runner.php:73
Cake\Http\Runner->handle
CORE/src/Http/Runner.php:58
Cake\Http\Runner->run
CORE/src/Http/Server.php:90
Cake\Http\Server->run
ROOT/webroot/index.php:40
/var/www/personal/easyupp/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php
Toggle Arguments
        if ($this->_compareToken($header, $cookie)) {
            return;
        }
        throw new InvalidCsrfTokenException(__d('cake', 'Missing CSRF token body'));
    }
    /**
     * Ensure that the request token matches the cookie value and that

middleware:

    public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
    {
        Configure::load('easyupp/frontend', 'default');
        $policies = Configure::read('Frontend.ContentSecurityPolicy');

        $securityHeaders = new SecurityHeadersMiddleware();
        $securityHeaders
            ->setCrossDomainPolicy()
            ->setReferrerPolicy()
            ->setXFrameOptions()
            ->setXssProtection()
            ->noOpen()
            ->noSniff();

        $middlewareQueue
            ->add($securityHeaders)
            ->add(new CspMiddleware($policies))
            // Catch any exceptions in the lower layers,
            // and make an error page/response
            ->add(new ErrorHandlerMiddleware(Configure::read('Error')))
            // https://github.com/dereuromark/cakephp-setup/blob/master/docs/Maintenance/Maintenance.md
            ->add(MaintenanceMiddleware::class)
            // Handle plugin/theme assets like CakePHP normally does.
            ->add(new AssetMiddleware([
                'cacheTime' => Configure::read('Asset.cacheTime'),
            ]))
            ->add(new RoutingMiddleware($this));

        return $middlewareQueue;
    }

The site is also using the FormProtection component, but disabling this had no effect when debugging this.

What you expected to happen

Not to get this error.

@dereuromark dereuromark added this to the 4.0.7 milestone Apr 19, 2020
@ADmad
Copy link
Member

ADmad commented Apr 19, 2020

Must be related to #14431.

@markstory
Copy link
Member

This happens on any form submission. A workaround is clearing cookie, but is it reasonable to force clearing this data on each release to avoid any potential CSRF errors?

Unfortunately we needed to change how the CSRF tokens were generated in this release, which is what is causing this mismatch. One way to help mitigate this would be to set a short expiry on your CSRF tokens for a period of time so that browsers clear the cookies and renew the cookie, or clear the CSRF token on logout/login/session expiration.

@othercorey
Copy link
Member

Maybe we can update the bakery post to explain that the token is also generated differently instead of just saying we validate it better.

@cnizzardini
Copy link
Contributor Author

cnizzardini commented Apr 20, 2020

I guess I will have to add something into the application to handle this when I upgrade to 4.0.6. Do you have anything in mind that can be done within cake internals to handle this instead? If so, I'll just wait until 4.0.7.

Like, is there a way to detect the old style of token and expire the cookie automatically? This would probably assist the community. I've already seen one other user report this same issue in the slack chat.

@markstory
Copy link
Member

The previous style tokens will look like invalid ones to the new code. We could add a configuration option to continue accepting the previous style tokens. That would allow a smoother upgrade.

@sharkooon
Copy link

Got the same error on a fresh new project i created an hour ago.
Setup database and baked all from tables.
Didn't add anything to Application.php, so just from the default app template.

When i submit the baked form i got the: "Missing CSRF token body".
Removing cookies didn't solve it.

What should i do? Using 4.05?

@impronta48
Copy link

Hi,
I managed to solve clearing all the cookies when EDITING.
Anyway I still get this error on the DELETE action (baked).

How can I solve?
Thanks
Massimo

@cnizzardini
Copy link
Contributor Author

I wonder if one solution here is for Cake to read both tokens, but only write the new token. This would eventually phase out the problem tokens without causing issues for the user base. I haven't looked at the code myself, but maybe a cake core dev would know off the top of their head?

@cnizzardini
Copy link
Contributor Author

cnizzardini commented Apr 21, 2020

After reading through 1cee60b a simple modification to _validateToken in CsrfProtectionMiddleware.php seems to make this fix backward compatible.

    protected function _validateToken(ServerRequestInterface $request): void
    {
        $cookie = Hash::get($request->getCookieParams(), $this->_config['cookieName']);

        if (!$cookie) {
            throw new InvalidCsrfTokenException(__d('cake', 'Missing CSRF token cookie'));
        }

        $body = $request->getParsedBody();
        if (is_array($body) || $body instanceof ArrayAccess) {
            $post = Hash::get($body, $this->_config['field']);
            if (Security::constantEquals($post, $cookie)) {
                return;
            } else if ($this->_compareToken($post, $cookie)) {
                return;
            }
        }

        $header = $request->getHeaderLine('X-CSRF-Token');
        if (Security::constantEquals($header, $cookie)) {
            return;
        } else if ($this->_compareToken($header, $cookie)) {
            return;
        }

        throw new InvalidCsrfTokenException(__d('cake', 'Missing CSRF token body'));
    }

@cnizzardini
Copy link
Contributor Author

I think this is a reasonable solution and then remove support for old tokens in 4.1 as was brought up in #14431

@markstory
Copy link
Member

@sharkooon @impronta48 I'm not able to reproduce the CSRF problems on delete actions. Have you checked to make sure that the forms created by FormHelper are including the _csrfToken hidden field?

If your application is hosted on the same domain as another CakePHP application you'll need to clear your cookies when going between applications as cookies are set per domain.

@cnizzardini Accepting the old tokens is a reasonable compromise to me. Do you want to make a pull request for that change?

@cnizzardini
Copy link
Contributor Author

@markstory I can if you are willing to wait a day or so. There is a failing unit test with my change, which makes sense given the change you made. No time tonight.

@markstory
Copy link
Member

@cnizzardini I'm good with waiting. If you need help with the tests you can open the pull request with the failing test and I can help out.

@cnizzardini
Copy link
Contributor Author

PR has a failing unit test. I wasn't exactly sure how to tackle that. Interested in how that will be written now.

@markstory
Copy link
Member

markstory commented Apr 27, 2020

Fixed in #14504

@iarcas-com-br
Copy link

Hello, I'm using version 4.0.7, I got this error.

I'm trying to use Login cakephp-tinyauth

but after going through the form I get the error, from line 275 of the file /vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php

I'snt was able to verify the return that the getHeaderLine ('X-CSRF-Token') try find, on line 270. And not exist X-CSRF-Token in $ request-> getHeaders ().

@othercorey
Copy link
Member

Please open a new issue.

@iarcas-com-br
Copy link

@othercorey sorry. #14550

@drzeitraum
Copy link

drzeitraum commented Aug 13, 2020

Version 4.1.2. Try edit form action and I get same error.
@cnizzardini is right. #14471 (comment)

@cnizzardini
Copy link
Contributor Author

I think this has been resolved @drzeitraum try upgrading to >= 4.0.9

@drzeitraum
Copy link

@cnizzardini thank's, I think so too. Just check new v4. But still like 3.7 more

@othercorey
Copy link
Member

I'm locking this. Please open a new ticket if you have an issue.

@cakephp cakephp locked as resolved and limited conversation to collaborators Aug 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

9 participants