ソースを参照

Merge pull request #14805 from cakephp/fix-double-csrf

Throw an error when the csrfToken attribute is already set
Mark Sch 5 年 前
コミット
74b320a4fc

+ 9 - 0
src/Http/Middleware/CsrfProtectionMiddleware.php

@@ -27,6 +27,7 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
+use RuntimeException;
 
 /**
  * Provides CSRF protection & validation.
@@ -122,6 +123,14 @@ class CsrfProtectionMiddleware implements MiddlewareInterface
 
             return $handler->handle($request);
         }
+        if ($request->getAttribute('csrfToken')) {
+            throw new RuntimeException(
+                'A CSRF token is already set in the request.' .
+                "\n" .
+                'Ensure you do not have the CSRF middleware applied more than once. ' .
+                'Check both your `Application::middleware()` method and `config/routes.php`.'
+            );
+        }
 
         $cookies = $request->getCookieParams();
         $cookieData = Hash::get($cookies, $this->_config['cookieName']);

+ 21 - 0
tests/TestCase/Http/Middleware/CsrfProtectionMiddlewareTest.php

@@ -26,6 +26,7 @@ use Cake\TestSuite\TestCase;
 use Laminas\Diactoros\Response as DiactorosResponse;
 use Laminas\Diactoros\Response\RedirectResponse;
 use Psr\Http\Message\ServerRequestInterface;
+use RuntimeException;
 use TestApp\Http\TestRequestHandler;
 
 /**
@@ -144,6 +145,26 @@ class CsrfProtectionMiddlewareTest extends TestCase
     }
 
     /**
+     * Test that double applying CSRF causes a failure.
+     *
+     * @return void
+     */
+    public function testDoubleApplicationFailure()
+    {
+        $request = new ServerRequest([
+            'environment' => ['REQUEST_METHOD' => 'GET'],
+        ]);
+        $request = $request->withAttribute('csrfToken', 'not-good');
+        $handler = new TestRequestHandler(function () {
+            return new RedirectResponse('/');
+        });
+
+        $middleware = new CsrfProtectionMiddleware();
+        $this->expectException(RuntimeException::class);
+        $middleware->process($request, $handler);
+    }
+
+    /**
      * Test that the CSRF tokens are set for diactoros responses
      *
      * @return void