diff --git a/typo3/sysext/core/Classes/Security/Nonce.php b/typo3/sysext/core/Classes/Security/Nonce.php index 1893231432b6..43f7b4ca2032 100644 --- a/typo3/sysext/core/Classes/Security/Nonce.php +++ b/typo3/sysext/core/Classes/Security/Nonce.php @@ -45,7 +45,7 @@ public static function fromHashSignedJwt(string $jwt): self $payload = self::decodeJwt($jwt, self::createSigningKeyFromEncryptionKey(Nonce::class), true); return GeneralUtility::makeInstance( self::class, - StringUtility::base64urlDecode($payload['nonce'] ?? ''), + StringUtility::base64urlDecode($payload['nonce'] ?? '', true), \DateTimeImmutable::createFromFormat(\DateTimeImmutable::RFC3339, $payload['time'] ?? null) ); } catch (\Throwable $t) { diff --git a/typo3/sysext/core/Classes/Utility/StringUtility.php b/typo3/sysext/core/Classes/Utility/StringUtility.php index 884805e20f27..22ce4ee7e4f2 100644 --- a/typo3/sysext/core/Classes/Utility/StringUtility.php +++ b/typo3/sysext/core/Classes/Utility/StringUtility.php @@ -189,11 +189,12 @@ public static function base64urlEncode(string $value): string * + position #63: `_` (underscore) -> `/` * * @param string $value base64url decoded string - * @return string raw value + * @param bool $strict enforces to only allow characters contained in the base64(url) alphabet + * @return string|false raw value, or `false` if non-base64(url) characters were given in strict mode */ - public static function base64urlDecode(string $value): string + public static function base64urlDecode(string $value, bool $strict = false): string|false { - return base64_decode(strtr($value, ['-' => '+', '_' => '/'])); + return base64_decode(strtr($value, ['-' => '+', '_' => '/']), $strict); } /** diff --git a/typo3/sysext/core/Tests/Unit/Utility/StringUtilityTest.php b/typo3/sysext/core/Tests/Unit/Utility/StringUtilityTest.php index ff7eb41957bb..9eaeedf7d793 100644 --- a/typo3/sysext/core/Tests/Unit/Utility/StringUtilityTest.php +++ b/typo3/sysext/core/Tests/Unit/Utility/StringUtilityTest.php @@ -389,6 +389,32 @@ public function base64urlDecodeWorks(string $rawValue, string $encodedValue): vo self::assertSame($rawValue, StringUtility::base64urlDecode($encodedValue)); } + public static function base64urlStrictDataProvider(): \Generator + { + yield ['', '']; + yield ['YQ', 'a']; + yield ['YWE', 'aa']; + yield ['YWE-', 'aa>']; + yield ['YWE_', 'aa?']; + yield ['YWFh', 'aaa']; + yield ['YWFhYQ', 'aaaa']; + yield ['YWFhYQ!', false]; + yield ['Y!W!E', false]; + // `Y W E` is interesting - plain `base64_decode` strips inner spaces + yield ['Y W E', 'aa']; + yield ["Y\nW\nE", 'aa']; + yield ["Y\tW\tE", 'aa']; + } + + /** + * @test + * @dataProvider base64urlStrictDataProvider + */ + public function base64urlStrictDecodeWorks(string $encodedValue, string|bool $expectation): void + { + self::assertSame($expectation, StringUtility::base64urlDecode($encodedValue, true)); + } + public static function explodeEscapedDataProvider(): array { return [