diff --git a/system/Security/Security.php b/system/Security/Security.php index 24bc5c670c8d..fa449c5cc60b 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -327,8 +327,9 @@ private function getPostedToken(RequestInterface $request): ?string } parse_str($body, $parsed); + $tokenValue = $parsed[$this->config->tokenName] ?? null; - return $parsed[$this->config->tokenName] ?? null; + return is_string($tokenValue) ? $tokenValue : null; } return null; diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index ad181ce1eecc..b5f37223c9b3 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -316,7 +316,7 @@ public function testGetters(): void $this->assertIsBool($security->shouldRedirect()); } - public function testGetPostedTokenReturnsTokenWhenValid(): void + public function testGetPostedTokenReturnsTokenFromPost(): void { $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $request = $this->createIncomingRequest(); @@ -325,25 +325,16 @@ public function testGetPostedTokenReturnsTokenWhenValid(): void $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsNullWhenEmpty(): void + public function testGetPostedTokenReturnsTokenFromHeader(): void { $_POST = []; - $request = $this->createIncomingRequest(); + $request = $this->createIncomingRequest()->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - $this->assertNull($method($request)); - } - - public function testGetPostedTokenReturnsNullWhenMaliciousData(): void - { - $_POST['csrf_test_name'] = ['malicious' => 'data']; - $request = $this->createIncomingRequest(); - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - - $this->assertNull($method($request)); + $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsTokenFromJsonInput(): void + public function testGetPostedTokenReturnsTokenFromJsonBody(): void { $_POST = []; $jsonBody = json_encode(['csrf_test_name' => '8b9218a55906f9dcc1dc263dce7f005a']); @@ -353,7 +344,7 @@ public function testGetPostedTokenReturnsTokenFromJsonInput(): void $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsTokenFromFormEncodedInput(): void + public function testGetPostedTokenReturnsTokenFromFormBody(): void { $_POST = []; $formBody = 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a'; @@ -363,13 +354,24 @@ public function testGetPostedTokenReturnsTokenFromFormEncodedInput(): void $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } - public function testGetPostedTokenReturnsNullFromMaliciousJsonInput(): void + public function testGetPostedTokenReturnsNullForInvalidInputs(): void { - $_POST = []; - $maliciousJson = json_encode(['csrf_test_name' => ['malicious' => 'data']]); - $request = $this->createIncomingRequest()->setBody($maliciousJson); - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); - - $this->assertNull($method($request)); + $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + $testCases = [ + 'empty_post' => $this->createIncomingRequest(), + 'malicious_post' => $this->createIncomingRequest()->setGlobal('post', ['csrf_test_name' => ['malicious' => 'data']]), + 'empty_header' => $this->createIncomingRequest()->setHeader('X-CSRF-TOKEN', ''), + 'malicious_json' => $this->createIncomingRequest()->setBody(json_encode(['csrf_test_name' => ['malicious' => 'data']])), + 'invalid_json' => $this->createIncomingRequest()->setBody('{invalid json}'), + 'missing_token_in_body' => $this->createIncomingRequest()->setBody('other=value&another=test'), + 'malicious_form' => $this->createIncomingRequest()->setBody('csrf_test_name[]=malicious'), + ]; + + foreach ($testCases as $case => $request) { + $this->assertNull( + $method($request), + "Failed asserting that {$case} returns null" + ); + } } }