From 3899cd84874974619e58a6252763652bcf7b3a04 Mon Sep 17 00:00:00 2001 From: Franz Liedke Date: Wed, 12 Jun 2019 22:14:36 +0200 Subject: [PATCH] Accept CSRF token in request body as well --- .../src/Http/Middleware/CheckCsrfToken.php | 3 +- .../csrf_protection/RequireCsrfTokenTest.php | 61 ++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/framework/core/src/Http/Middleware/CheckCsrfToken.php b/framework/core/src/Http/Middleware/CheckCsrfToken.php index d3efe18fd..0d22ba340 100644 --- a/framework/core/src/Http/Middleware/CheckCsrfToken.php +++ b/framework/core/src/Http/Middleware/CheckCsrfToken.php @@ -39,7 +39,8 @@ class CheckCsrfToken implements Middleware private function tokensMatch(Request $request): bool { $expected = (string) $request->getAttribute('session')->token(); - $provided = $request->getHeaderLine('X-CSRF-Token'); // TODO: Use form field, if provided + $provided = $request->getParsedBody()['csrfToken'] ?? + $request->getHeaderLine('X-CSRF-Token'); return hash_equals($expected, $provided); } diff --git a/framework/core/tests/integration/api/csrf_protection/RequireCsrfTokenTest.php b/framework/core/tests/integration/api/csrf_protection/RequireCsrfTokenTest.php index fc518a588..e0cc6755d 100644 --- a/framework/core/tests/integration/api/csrf_protection/RequireCsrfTokenTest.php +++ b/framework/core/tests/integration/api/csrf_protection/RequireCsrfTokenTest.php @@ -97,7 +97,7 @@ class RequireCsrfTokenTest extends TestCase /** * @test */ - public function cookie_auth_succeeds_with_csrf_token() + public function cookie_auth_succeeds_with_csrf_token_in_header() { $initial = $this->server->handle( (new ServerRequest([], [], '/', 'GET')) @@ -155,6 +155,65 @@ class RequireCsrfTokenTest extends TestCase ); } + /** + * @test + */ + public function cookie_auth_succeeds_with_csrf_token_in_body() + { + $initial = $this->server->handle( + (new ServerRequest([], [], '/', 'GET')) + ); + + $token = $initial->getHeaderLine('X-CSRF-Token'); + $cookies = array_reduce( + $initial->getHeader('Set-Cookie'), + function ($memo, $setCookieString) { + $setCookie = SetCookie::fromSetCookieString($setCookieString); + $memo[$setCookie->getName()] = $setCookie->getValue(); + return $memo; + }, + [] + ); + + $auth = $this->server->handle( + (new ServerRequest([], [], '/login', 'POST')) + ->withBody(new CallbackStream(function () use ($token) { + return '{"identification": "admin", "password": "password", "csrfToken": "'.$token.'"}'; + })) + ->withCookieParams($cookies) + ->withHeader('Content-Type', 'application/json') + ); + + $token = $auth->getHeaderLine('X-CSRF-Token'); + $cookies = array_reduce( + $auth->getHeader('Set-Cookie'), + function ($memo, $setCookieString) { + $setCookie = SetCookie::fromSetCookieString($setCookieString); + $memo[$setCookie->getName()] = $setCookie->getValue(); + return $memo; + }, + [] + ); + + $response = $this->server->handle( + (new ServerRequest([], [], '/api/settings', 'POST')) + ->withBody(new CallbackStream(function () use ($token) { + return '{"mail_driver": "log", "csrfToken": "'.$token.'"}'; + })) + ->withCookieParams($cookies) + ->withHeader('Content-Type', 'application/json') + ); + + // Successful response? + $this->assertEquals(204, $response->getStatusCode()); + + // Was the setting actually changed in the database? + $this->assertEquals( + 'log', + $this->database()->table('settings')->where('key', 'mail_driver')->first()->value + ); + } + /** * @test */