From df486372ea56fac241d3c96ad43a7729fee64557 Mon Sep 17 00:00:00 2001
From: Benjamin Franzke <ben@bnf.dev>
Date: Tue, 13 Feb 2024 10:06:01 +0100
Subject: [PATCH] [SECURITY] Do not disclose encryptionKey via InstallTool

The encryptionKey is a secret that must never be sent within any
request, therefore it is now dropped from the editing interface in
"Configure Installation-Wide Options".

Resolves: #103046
Releases: main, 13.0, 12.4, 11.5
Change-Id: I260a8a2e9af29908543dfe48ac3658d8c45cc440
Security-Bulletin: TYPO3-CORE-SA-2024-004
Security-References: CVE-2024-25119
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82948
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
---
 .../Classes/Configuration/ConfigurationManager.php   |  1 +
 typo3/sysext/core/Classes/Log/Writer/FileWriter.php  | 12 +++++++++++-
 .../core/Configuration/DefaultConfiguration.php      |  1 -
 .../DefaultConfigurationDescription.yaml             |  3 ---
 .../TypoScript/Parser/TypoScriptParserTest.php       |  2 ++
 .../Mvc/Web/Routing/UriBuilderTest.php               |  7 +++++++
 6 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/typo3/sysext/core/Classes/Configuration/ConfigurationManager.php b/typo3/sysext/core/Classes/Configuration/ConfigurationManager.php
index be665302ded5..8b359c18cdc3 100644
--- a/typo3/sysext/core/Classes/Configuration/ConfigurationManager.php
+++ b/typo3/sysext/core/Classes/Configuration/ConfigurationManager.php
@@ -66,6 +66,7 @@ class ConfigurationManager
         'EXTCONF',
         'DB',
         'SYS/caching/cacheConfigurations',
+        'SYS/encryptionKey',
         'SYS/session',
         'EXTENSIONS',
     ];
diff --git a/typo3/sysext/core/Classes/Log/Writer/FileWriter.php b/typo3/sysext/core/Classes/Log/Writer/FileWriter.php
index f01b3a9f21a8..2acf19f06c12 100644
--- a/typo3/sysext/core/Classes/Log/Writer/FileWriter.php
+++ b/typo3/sysext/core/Classes/Log/Writer/FileWriter.php
@@ -66,7 +66,10 @@ class FileWriter extends AbstractWriter
     {
         // the parent constructor reads $options and sets them
         parent::__construct($options);
-        if (empty($options['logFile'])) {
+        if (empty($options['logFile']) &&
+            // omit logging if TYPO3 has not been configured (avoid creating a guessable filename)
+            ($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] ?? '') !== ''
+        ) {
             $this->setLogFile($this->getDefaultLogFileName());
         }
     }
@@ -76,6 +79,9 @@ class FileWriter extends AbstractWriter
      */
     public function __destruct()
     {
+        if ($this->logFile === '') {
+            return;
+        }
         self::$logFileHandlesCount[$this->logFile]--;
         if (self::$logFileHandlesCount[$this->logFile] <= 0) {
             $this->closeLogFile();
@@ -130,6 +136,10 @@ class FileWriter extends AbstractWriter
      */
     public function writeLog(LogRecord $record)
     {
+        if ($this->logFile === '') {
+            return $this;
+        }
+
         $data = '';
         $context = $record->getData();
         $message = $record->getMessage();
diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php
index a61c88d7485a..f72582bfd578 100644
--- a/typo3/sysext/core/Configuration/DefaultConfiguration.php
+++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php
@@ -81,7 +81,6 @@ return [
         ],
         'createGroup' => '',
         'sitename' => 'TYPO3',
-        'encryptionKey' => '',
         'cookieDomain' => '',
         'trustedHostsPattern' => 'SERVER_NAME',
         'devIPmask' => '127.0.0.1,::1',
diff --git a/typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml b/typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml
index e2e5b10d16f5..89b5cca33669 100644
--- a/typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml
+++ b/typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml
@@ -76,9 +76,6 @@ SYS:
         sitename:
             type: text
             description: 'Name of the base-site.'
-        encryptionKey:
-            type: text
-            description: 'This is a "salt" used for various kinds of encryption, CRC checksums and validations. You can enter any rubbish string here but try to keep it secret. You should notice that a change to this value might invalidate temporary information, URLs etc. At least, clear all cache if you change this so any such information can be rebuilt with the new key.'
         cookieDomain:
             type: text
             description: 'Restricts the domain name for FE and BE session cookies. When setting the value to ".domain.com" (replace domain.com with your domain!), login sessions will be shared across subdomains. Alternatively, if you have more than one domain with sub-domains, you can set the value to a regular expression to match against the domain of the HTTP request. The result of the match is used as the domain for the cookie. eg. <code>/\.(example1|example2)\.com$/</code> or <code>/\.(example1\.com)|(example2\.net)$/</code>. Separate domains for FE and BE can be set using <a href="#FE-cookieDomain">$TYPO3_CONF_VARS[''FE''][''cookieDomain'']</a> and <a href="#BE-cookieDomain">$TYPO3_CONF_VARS[''BE''][''cookieDomain'']</a> respectively.'
diff --git a/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/Parser/TypoScriptParserTest.php b/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/Parser/TypoScriptParserTest.php
index 0911003ba1c3..c2db2b2fde5e 100644
--- a/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/Parser/TypoScriptParserTest.php
+++ b/typo3/sysext/core/Tests/UnitDeprecated/TypoScript/Parser/TypoScriptParserTest.php
@@ -667,7 +667,9 @@ test.TYPO3Forever.TypoScript = 1
      */
     public function importFiles(string $typoScript, string $expected): void
     {
+        $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = 'secret-encryption-key-test';
         $resolvedIncludeLines = TypoScriptParser::checkIncludeLines($typoScript);
+        unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']);
         self::assertEquals($expected, $resolvedIncludeLines);
     }
 
diff --git a/typo3/sysext/extbase/Tests/UnitDeprecated/Mvc/Web/Routing/UriBuilderTest.php b/typo3/sysext/extbase/Tests/UnitDeprecated/Mvc/Web/Routing/UriBuilderTest.php
index d50addfc1993..efaea1884cba 100644
--- a/typo3/sysext/extbase/Tests/UnitDeprecated/Mvc/Web/Routing/UriBuilderTest.php
+++ b/typo3/sysext/extbase/Tests/UnitDeprecated/Mvc/Web/Routing/UriBuilderTest.php
@@ -37,6 +37,7 @@ final class UriBuilderTest extends UnitTestCase
     {
         parent::setUp();
         $this->mockExtensionService = $this->createMock(ExtensionService::class);
+        $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = 'secret-encryption-key-test';
         $this->subject = $this->getAccessibleMock(UriBuilder::class, ['build']);
         $this->subject->setRequest($this->createMock(Request::class));
         $this->subject->injectConfigurationManager($this->createMock(ConfigurationManagerInterface::class));
@@ -44,6 +45,12 @@ final class UriBuilderTest extends UnitTestCase
         $this->subject->_set('contentObject', $this->createMock(ContentObjectRenderer::class));
     }
 
+    protected function tearDown(): void
+    {
+        unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']);
+        parent::tearDown();
+    }
+
     /**
      * @test
      */
-- 
GitLab