diff --git a/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/ContentSecurityPolicyHeader.php b/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/ContentSecurityPolicyHeader.php index 3919ab4f8dbd8d39b19dd4d2d72a391629eb8e7c..e86de5f5cf5e28e039995f9a3da5bb8cea7ae60b 100644 --- a/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/ContentSecurityPolicyHeader.php +++ b/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/ContentSecurityPolicyHeader.php @@ -48,8 +48,9 @@ class ContentSecurityPolicyHeader return empty($this->directives); } - public function mitigatesCrossSiteScripting(): bool + public function mitigatesCrossSiteScripting(string $fileName = null): bool { + $isSvg = str_ends_with($fileName ?? '', '.svg'); $defaultSrc = isset($this->directives['default-src']) ? $this->directiveMitigatesCrossSiteScripting($this->directives['default-src']) : null; @@ -58,6 +59,7 @@ class ContentSecurityPolicyHeader : null; $styleSrc = isset($this->directives['style-src']) ? $this->directiveMitigatesCrossSiteScripting($this->directives['style-src']) + || ($isSvg && $this->directives['style-src']->hasInstructions('unsafe-inline')) : null; $objectSrc = isset($this->directives['object-src']) ? $this->directiveMitigatesCrossSiteScripting($this->directives['object-src']) diff --git a/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/FileDeclaration.php b/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/FileDeclaration.php index 2053123696852f9894c54728ad17119a69ecdd66..b085f1c4a3375120554e3d0832b507ab87d7cdbb 100644 --- a/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/FileDeclaration.php +++ b/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/FileDeclaration.php @@ -122,7 +122,7 @@ class FileDeclaration { $mismatches = []; if ($this->handler instanceof \Closure) { - $result = $this->handler->call($this, $response); + $result = $this->handler->call($this, $this, $response); if ($result !== null) { $mismatches[] = $result; } diff --git a/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/ServerResponseCheck.php b/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/ServerResponseCheck.php index d252a420a5821a465c999a173100d4530b414008..b686e9d2459c40168a16eef47504f5ac27315f2f 100644 --- a/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/ServerResponseCheck.php +++ b/typo3/sysext/install/Classes/SystemEnvironment/ServerResponse/ServerResponseCheck.php @@ -137,7 +137,7 @@ class ServerResponseCheck implements CheckInterface protected function initializeFileDeclarations(string $fileName): array { - $cspClosure = function (ResponseInterface $response): ?StatusMessage { + $cspClosure = function (FileDeclaration $fileDeclaration, ResponseInterface $response): ?StatusMessage { $cspHeader = new ContentSecurityPolicyHeader( $response->getHeaderLine('content-security-policy') ); @@ -147,7 +147,7 @@ class ServerResponseCheck implements CheckInterface 'missing Content-Security-Policy for this location' ); } - if (!$cspHeader->mitigatesCrossSiteScripting()) { + if (!$cspHeader->mitigatesCrossSiteScripting($fileDeclaration->getFileName())) { return new StatusMessage( 'weak Content-Security-Policy for this location "%s"', $response->getHeaderLine('content-security-policy') diff --git a/typo3/sysext/install/Tests/Unit/SystemEnvironment/ServerResponse/ContentSecurityPolicyHeaderTest.php b/typo3/sysext/install/Tests/Unit/SystemEnvironment/ServerResponse/ContentSecurityPolicyHeaderTest.php index df9342be585323876395b7174d98fb35ddfdc426..ac437e2c2fc700873ac39b43539847bf765fd50c 100644 --- a/typo3/sysext/install/Tests/Unit/SystemEnvironment/ServerResponse/ContentSecurityPolicyHeaderTest.php +++ b/typo3/sysext/install/Tests/Unit/SystemEnvironment/ServerResponse/ContentSecurityPolicyHeaderTest.php @@ -27,48 +27,69 @@ class ContentSecurityPolicyHeaderTest extends TestCase return [ '#1' => [ '', + null, false, ], '#2' => [ "default-src 'none'", + null, true, ], '#3' => [ "script-src 'none'", + null, false, ], '#4' => [ "style-src 'none'", + null, false, ], '#5' => [ "default-src 'none'; script-src 'none'", + null, true, ], '#6' => [ "default-src 'none'; style-src 'none'", + null, true, ], '#7' => [ "default-src 'none'; object-src 'none'", + null, true, ], '#8' => [ "default-src 'none'; script-src 'self'; style-src 'self'; object-src 'self'", + null, false, ], '#9' => [ "script-src 'none'; style-src 'none'; object-src 'none'", + null, true, ], '#10' => [ "default-src 'none'; script-src 'unsafe-eval'; style-src 'none'; object-src 'none'", + null, false, ], '#11' => [ "default-src 'none'; script-src 'unsafe-inline'; style-src 'none'; object-src 'none'", + null, false, ], + '#12' => [ + "default-src 'self'; script-src 'none'; style-src 'unsafe-inline'; object-src 'none'", + null, + false, + ], + '#13' => [ + "default-src 'self'; script-src 'none'; style-src 'unsafe-inline'; object-src 'none'", + 'file.svg', + true, + ], ]; } @@ -79,9 +100,9 @@ class ContentSecurityPolicyHeaderTest extends TestCase * @test * @dataProvider mitigatesCrossSiteScriptingDataProvider */ - public function mitigatesCrossSiteScripting(string $header, bool $expectation): void + public function mitigatesCrossSiteScripting(string $header, ?string $fileName, $expectation): void { $subject = new ContentSecurityPolicyHeader($header); - self::assertSame($expectation, $subject->mitigatesCrossSiteScripting()); + self::assertSame($expectation, $subject->mitigatesCrossSiteScripting($fileName)); } }