diff --git a/typo3/sysext/core/Tests/Functional/Html/DefaultSanitizerBuilderTest.php b/typo3/sysext/core/Tests/Functional/Html/DefaultSanitizerBuilderTest.php index a7f52eb242f8aeea8c27c0a5be533f3620e0c8ad..6e4d74335d11aadff1a3a66945f337abc1b9b5b8 100644 --- a/typo3/sysext/core/Tests/Functional/Html/DefaultSanitizerBuilderTest.php +++ b/typo3/sysext/core/Tests/Functional/Html/DefaultSanitizerBuilderTest.php @@ -17,8 +17,12 @@ declare(strict_types=1); namespace TYPO3\CMS\Core\Tests\Functional\Html; +use Psr\Log\LogLevel; use TYPO3\CMS\Core\Html\DefaultSanitizerBuilder; use TYPO3\CMS\Core\Html\SanitizerBuilderFactory; +use TYPO3\CMS\Core\Html\SanitizerInitiator; +use TYPO3\CMS\Core\Log\LogRecord; +use TYPO3\CMS\Core\Tests\Functional\Fixtures\Log\DummyWriter; use TYPO3\CMS\Core\Tests\Functional\Html\Fixtures\ExtendedSanitizerBuilder; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\HtmlSanitizer\Behavior; @@ -32,6 +36,26 @@ class DefaultSanitizerBuilderTest extends FunctionalTestCase */ protected $initializeDatabase = false; + protected $configurationToUseInTestInstance = [ + 'LOG' => [ + 'TYPO3' => [ + 'HtmlSanitizer' => [ + 'writerConfiguration' => [ + LogLevel::DEBUG => [ + DummyWriter::class => [], + ], + ], + ], + ], + ], + ]; + + protected function tearDown(): void + { + parent::tearDown(); + DummyWriter::$logs = []; + } + public static function isSanitizedDataProvider(): array { return [ @@ -187,6 +211,25 @@ class DefaultSanitizerBuilderTest extends FunctionalTestCase ); } + /** + * @test + */ + public function incidentIsLogged(): void + { + $trace = bin2hex(random_bytes(8)); + $sanitizer = (new DefaultSanitizerBuilder())->build(); + $sanitizer->sanitize('<script>alert(1)</script>', new SanitizerInitiator($trace)); + $logItemDataExpectation = [ + 'behavior' => 'default', + 'nodeName' => 'script', + 'initiator' => $trace, + ]; + $logItem = end(DummyWriter::$logs); + self::assertInstanceOf(LogRecord::class, $logItem); + self::assertSame($logItemDataExpectation, $logItem->getData()); + self::assertSame('TYPO3.HtmlSanitizer.Visitor.CommonVisitor', $logItem->getComponent()); + } + private function resolveBehaviorFromSanitizer(Sanitizer $sanitizer): Behavior { $visitorsProp = (new \ReflectionObject($sanitizer))->getProperty('visitors'); diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/Sanitize/HtmlViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/Sanitize/HtmlViewHelper.php index 03c91b39810361159527516a32bce87cfc2ebc64..17a0ae3513e92aa0b8b1cbabb738368d3e75bf26 100644 --- a/typo3/sysext/fluid/Classes/ViewHelpers/Sanitize/HtmlViewHelper.php +++ b/typo3/sysext/fluid/Classes/ViewHelpers/Sanitize/HtmlViewHelper.php @@ -18,6 +18,7 @@ declare(strict_types=1); namespace TYPO3\CMS\Fluid\ViewHelpers\Sanitize; use TYPO3\CMS\Core\Html\SanitizerBuilderFactory; +use TYPO3\CMS\Core\Html\SanitizerInitiator; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\HtmlSanitizer\Builder\BuilderInterface; use TYPO3\HtmlSanitizer\Sanitizer; @@ -94,7 +95,12 @@ class HtmlViewHelper extends AbstractViewHelper { $value = $renderChildrenClosure(); $build = $arguments['build'] ?? 'default'; - return static::createSanitizer($build)->sanitize((string)$value); + return static::createSanitizer($build)->sanitize((string)$value, self::createInitiator()); + } + + protected static function createInitiator(): SanitizerInitiator + { + return GeneralUtility::makeInstance(SanitizerInitiator::class, self::class); } protected static function createSanitizer(string $build): Sanitizer diff --git a/typo3/sysext/fluid/Tests/Functional/ViewHelpers/Sanitize/Fixtures/Template.html b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/Sanitize/Fixtures/Template.html new file mode 100644 index 0000000000000000000000000000000000000000..1b7f37c0579af2a36faf5f3ab01ba6fafcf94425 --- /dev/null +++ b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/Sanitize/Fixtures/Template.html @@ -0,0 +1,9 @@ +<html + xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" + xmlns:sg="http://typo3.org/ns/TYPO3/CMS/Styleguide/ViewHelpers" + data-namespace-typo3-fluid="true" +> + +<f:sanitize.html>{payload}</f:sanitize.html> + +</html> diff --git a/typo3/sysext/fluid/Tests/Functional/ViewHelpers/Sanitize/HtmlViewHelperTest.php b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/Sanitize/HtmlViewHelperTest.php index a688f1d9c4295600618140bfaae35da67815d749..e9aa43f1027d8576f5d93876807c5ecc19d16c6f 100644 --- a/typo3/sysext/fluid/Tests/Functional/ViewHelpers/Sanitize/HtmlViewHelperTest.php +++ b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/Sanitize/HtmlViewHelperTest.php @@ -17,8 +17,12 @@ declare(strict_types=1); namespace TYPO3\CMS\Fluid\Tests\Functional\ViewHelpers\Sanitize; +use Psr\Log\LogLevel; +use TYPO3\CMS\Core\Log\LogRecord; +use TYPO3\CMS\Core\Tests\Functional\Fixtures\Log\DummyWriter; use TYPO3\CMS\Core\Tests\Functional\Html\DefaultSanitizerBuilderTest; use TYPO3\CMS\Fluid\View\StandaloneView; +use TYPO3\CMS\Fluid\ViewHelpers\Sanitize\HtmlViewHelper; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; class HtmlViewHelperTest extends FunctionalTestCase @@ -28,6 +32,26 @@ class HtmlViewHelperTest extends FunctionalTestCase */ protected $initializeDatabase = false; + protected $configurationToUseInTestInstance = [ + 'LOG' => [ + 'TYPO3' => [ + 'HtmlSanitizer' => [ + 'writerConfiguration' => [ + LogLevel::DEBUG => [ + DummyWriter::class => [], + ], + ], + ], + ], + ], + ]; + + protected function tearDown(): void + { + parent::tearDown(); + DummyWriter::$logs = []; + } + public static function isSanitizedDataProvider(): array { // @todo splitter for functional tests cannot deal with external classes @@ -60,4 +84,26 @@ class HtmlViewHelperTest extends FunctionalTestCase $view->setTemplateSource('{payload -> f:sanitize.html()}'); self::assertSame($expectation, $view->render()); } + + /** + * @test + */ + public function incidentIsLogged(): void + { + $templatePath = __DIR__ . '/Fixtures/Template.html'; + $view = new StandaloneView(); + $view->setTemplatePathAndFilename($templatePath); + $view->assign('payload', '<script>alert(1)</script>'); + $view->render(); + + $logItemDataExpectation = [ + 'behavior' => 'default', + 'nodeName' => 'script', + 'initiator' => HtmlViewHelper::class, + ]; + $logItem = end(DummyWriter::$logs); + self::assertInstanceOf(LogRecord::class, $logItem); + self::assertSame($logItemDataExpectation, $logItem->getData()); + self::assertSame('TYPO3.HtmlSanitizer.Visitor.CommonVisitor', $logItem->getComponent()); + } }