diff --git a/typo3/sysext/core/Classes/Routing/PageRouter.php b/typo3/sysext/core/Classes/Routing/PageRouter.php index 3d61b4180b5a1e10bfbeec112f8b9a097488b00b..347e6282054b5cdaed365f1b577bd727bb2de459 100644 --- a/typo3/sysext/core/Classes/Routing/PageRouter.php +++ b/typo3/sysext/core/Classes/Routing/PageRouter.php @@ -39,6 +39,7 @@ use TYPO3\CMS\Core\Routing\Enhancer\RoutingEnhancerInterface; use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Frontend\Page\CacheHashCalculator; /** @@ -104,9 +105,12 @@ class PageRouter implements RouterInterface $candidateProvider = $this->getSlugCandidateProvider($this->context); // Legacy URIs (?id=12345) takes precedence, no matter if a route is given - $requestId = (int)($request->getQueryParams()['id'] ?? 0); - if ($requestId > 0) { - if (!empty($pageId = $candidateProvider->getRealPageIdForPageIdAsPossibleCandidate($requestId))) { + $requestId = ($request->getQueryParams()['id'] ?? null); + if ($requestId !== null) { + if (MathUtility::canBeInterpretedAsInteger($requestId) + && (int)$requestId > 0 + && !empty($pageId = $candidateProvider->getRealPageIdForPageIdAsPossibleCandidate((int)$requestId)) + ) { return new PageArguments( (int)$pageId, (string)($request->getQueryParams()['type'] ?? '0'), diff --git a/typo3/sysext/core/Classes/Routing/SiteMatcher.php b/typo3/sysext/core/Classes/Routing/SiteMatcher.php index 639080c0d3d67b73eacd8c8e11ffbe48595d9211..36ce7e35c5d35b11bc2c2ec10227ab2f18366d00 100644 --- a/typo3/sysext/core/Classes/Routing/SiteMatcher.php +++ b/typo3/sysext/core/Classes/Routing/SiteMatcher.php @@ -31,6 +31,7 @@ use TYPO3\CMS\Core\Site\Entity\SiteInterface; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Core\Utility\RootlineUtility; /** @@ -185,6 +186,9 @@ class SiteMatcher implements SingletonInterface if ($pageId === null) { return null; } + if (!MathUtility::canBeInterpretedAsInteger($pageId)) { + return null; + } return (int)$pageId <= 0 ? null : (int)$pageId; } @@ -197,6 +201,9 @@ class SiteMatcher implements SingletonInterface if ($languageId === null) { return null; } + if (!MathUtility::canBeInterpretedAsInteger($languageId)) { + return null; + } return (int)$languageId < 0 ? null : (int)$languageId; } diff --git a/typo3/sysext/frontend/Tests/Functional/SiteHandling/SiteRequestTest.php b/typo3/sysext/frontend/Tests/Functional/SiteHandling/SiteRequestTest.php index 8d050f2d35ea12cd397f4b1e9410487314d821b7..84c4ec6a82716aecc6931e54711d4e2a427632a9 100644 --- a/typo3/sysext/frontend/Tests/Functional/SiteHandling/SiteRequestTest.php +++ b/typo3/sysext/frontend/Tests/Functional/SiteHandling/SiteRequestTest.php @@ -17,7 +17,10 @@ declare(strict_types=1); namespace TYPO3\CMS\Frontend\Tests\Functional\SiteHandling; +use Psr\Http\Message\UriInterface; use TYPO3\CMS\Core\Core\Bootstrap; +use TYPO3\CMS\Core\Http\Uri; +use TYPO3\CMS\Core\Utility\HttpUtility; use TYPO3\CMS\Core\Utility\PermutationUtility; use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory; use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter; @@ -1057,4 +1060,51 @@ final class SiteRequestTest extends AbstractTestCase self::stringContains('ID was outside the domain') ); } + + public static function getUrisWithInvalidLegacyQueryParameters(): \Generator + { + $uri = new Uri('https://website.local/'); + yield '#0 id with float value having a zero decimal' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => '1110.0'])), + ]; + yield '#1 id string value with tailing numbers' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => 'step1110'])), + ]; + yield '#2 id string value with leading numbers' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => '1110step'])), + ]; + yield '#3 id string value without numbers' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => 'foobar'])), + ]; + yield '#4 id string value with a exponent' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => '11e10'])), + ]; + yield '#5 id with a zero as value' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => 0])), + ]; + } + + /** + * @test + * @dataProvider getUrisWithInvalidLegacyQueryParameters + */ + public function requestWithInvalidLegacyQueryParametersDisplayPageNotFoundPage(UriInterface $uri): void + { + $this->writeSiteConfiguration( + 'website-local', + $this->buildSiteConfiguration(1000, 'https://website.local/'), + [], + $this->buildErrorHandlingConfiguration('PHP', [404]) + ); + $response = $this->executeFrontendSubRequest( + new InternalRequest((string)$uri), + new InternalRequestContext() + ); + $json = json_decode((string)$response->getBody(), true); + self::assertSame(404, $response->getStatusCode()); + self::assertThat( + $json['message'] ?? null, + self::stringContains('The requested page does not exist') + ); + } } diff --git a/typo3/sysext/frontend/Tests/Functional/SiteHandling/SlugSiteRequestTest.php b/typo3/sysext/frontend/Tests/Functional/SiteHandling/SlugSiteRequestTest.php index 38a1cb4d2af8ec4ec6d4591afa10b0f8c396a440..32357b5cf6881f8baa8917e7d52ab43a8139334c 100644 --- a/typo3/sysext/frontend/Tests/Functional/SiteHandling/SlugSiteRequestTest.php +++ b/typo3/sysext/frontend/Tests/Functional/SiteHandling/SlugSiteRequestTest.php @@ -17,7 +17,10 @@ declare(strict_types=1); namespace TYPO3\CMS\Frontend\Tests\Functional\SiteHandling; +use Psr\Http\Message\UriInterface; use TYPO3\CMS\Core\Core\Bootstrap; +use TYPO3\CMS\Core\Http\Uri; +use TYPO3\CMS\Core\Utility\HttpUtility; use TYPO3\CMS\Core\Utility\PermutationUtility; use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory; use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter; @@ -2767,4 +2770,51 @@ final class SlugSiteRequestTest extends AbstractTestCase ); } } + + public static function getUrisWithInvalidLegacyQueryParameters(): \Generator + { + $uri = new Uri('https://website.local/welcome/'); + yield '#0 id with float value having a zero decimal' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => '1110.0'])), + ]; + yield '#1 id string value with tailing numbers' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => 'step1110'])), + ]; + yield '#2 id string value with leading numbers' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => '1110step'])), + ]; + yield '#3 id string value without numbers' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => 'foobar'])), + ]; + yield '#4 id string value with a exponent' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => '11e10'])), + ]; + yield '#5 id with a zero as value' => [ + 'uri' => $uri->withQuery(HttpUtility::buildQueryString(['id' => 0])), + ]; + } + + /** + * @test + * @dataProvider getUrisWithInvalidLegacyQueryParameters + */ + public function requestWithInvalidLegacyQueryParametersDisplayPageNotFoundPage(UriInterface $uri): void + { + $this->writeSiteConfiguration( + 'website-local', + $this->buildSiteConfiguration(1000, 'https://website.local/'), + [], + $this->buildErrorHandlingConfiguration('PHP', [404]) + ); + $response = $this->executeFrontendSubRequest( + new InternalRequest((string)$uri), + new InternalRequestContext() + ); + $json = json_decode((string)$response->getBody(), true); + self::assertSame(404, $response->getStatusCode()); + self::assertThat( + $json['message'] ?? null, + self::stringContains('The requested page does not exist') + ); + } }