From b9cabb72c2c348d7397e85bfb2348acabe31e8fb Mon Sep 17 00:00:00 2001 From: Oliver Hader <oliver@typo3.org> Date: Wed, 6 Dec 2023 23:01:13 +0100 Subject: [PATCH] [TASK] Add strict parameter to base64url decode PHP's base64_decode has a strict parameter to only accept characters of the corresponding base64 alphabet, see https://www.php.net/manual/en/function.base64-decode.php Resolves: #102620 Releases: main, 12.4 Change-Id: I39a038519ec1e884ba42f691c6dea76cbce772fe Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82271 Tested-by: core-ci <typo3@b13.com> Reviewed-by: Oliver Hader <oliver.hader@typo3.org> Tested-by: Oliver Hader <oliver.hader@typo3.org> --- typo3/sysext/core/Classes/Security/Nonce.php | 2 +- .../core/Classes/Utility/StringUtility.php | 7 ++--- .../Tests/Unit/Utility/StringUtilityTest.php | 26 +++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) 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 @@ class Nonce implements SigningSecretInterface $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 @@ class StringUtility * + 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 @@ final class StringUtilityTest extends UnitTestCase 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 [ -- GitLab