diff --git a/bundles/AdminBundle/Controller/Admin/SettingsController.php b/bundles/AdminBundle/Controller/Admin/SettingsController.php index d3480f9dee7..e27db6a75ec 100644 --- a/bundles/AdminBundle/Controller/Admin/SettingsController.php +++ b/bundles/AdminBundle/Controller/Admin/SettingsController.php @@ -46,8 +46,11 @@ use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Yaml\Yaml; +use enshrined\svgSanitize\Sanitizer; + /** * @Route("/settings") @@ -104,17 +107,30 @@ public function displayCustomLogoAction(Request $request) */ public function uploadCustomLogoAction(Request $request) { + $sourcePath = $_FILES['Filedata']['tmp_name']; $fileExt = File::getFileExtension($_FILES['Filedata']['name']); if (!in_array($fileExt, ['svg', 'png', 'jpg'])) { throw new \Exception('Unsupported file format'); } - if ($fileExt === 'svg' && stripos(file_get_contents($_FILES['Filedata']['tmp_name']), 'writeStream(self::CUSTOM_LOGO_PATH, fopen($_FILES['Filedata']['tmp_name'], 'rb')); + + $fileMimeType = MimeTypes::getDefault()->guessMimeType($sourcePath); + + if ($fileMimeType === 'image/svg+xml') { + $fileContent = file_get_contents($sourcePath); + + $sanitizer = new Sanitizer(); + $sanitizedFileContent = $sanitizer->sanitize($fileContent); + if ($sanitizedFileContent) { + $storage->write(self::CUSTOM_LOGO_PATH, $sanitizedFileContent); + }else{ + throw new \Exception('SVG Sanitization failed, probably due badly formatted XML. Filename:'.$sourcePath); + } + }else { + $storage->writeStream(self::CUSTOM_LOGO_PATH, fopen($sourcePath, 'rb')); + } // set content-type to text/html, otherwise (when application/json is sent) chrome will complain in // Ext.form.Action.Submit and mark the submission as failed diff --git a/bundles/CoreBundle/EventListener/AssetSanitizationListener.php b/bundles/CoreBundle/EventListener/AssetSanitizationListener.php new file mode 100644 index 00000000000..7463952ac6b --- /dev/null +++ b/bundles/CoreBundle/EventListener/AssetSanitizationListener.php @@ -0,0 +1,80 @@ + 'sanitizeAsset', + AssetEvents::PRE_UPDATE => 'sanitizeAsset', + ]; + } + + /** + * @param ElementEventInterface $e + */ + public function sanitizeAsset(ElementEventInterface $e) + { + $element = $e->getElement(); + + if ($element instanceof Asset\Image && $element->getDataChanged()) { + $assetStream = $element->getStream(); + + if (isset($assetStream)) { + $streamMetaData = stream_get_meta_data($assetStream); + $mime = MimeTypes::getDefault()->guessMimeType($streamMetaData['uri']); + + if ($mime === 'image/svg+xml') { + $sanitizedData = $this->sanitizeSVG(stream_get_contents($assetStream)); + $element->setData($sanitizedData); + } + } + } + } + + /** + * @param string $fileContent + * + * @return string + * + * @throws \Exception + */ + + protected function sanitizeSVG(string $fileContent) + { + $sanitizer = new Sanitizer(); + $sanitizedFileContent = $sanitizer->sanitize($fileContent); + + if (!$sanitizedFileContent) { + throw new \Exception('SVG Sanitization failed, probably due badly formatted XML.'); + } + + return $sanitizedFileContent; + } +} diff --git a/bundles/CoreBundle/Resources/config/event_listeners.yaml b/bundles/CoreBundle/Resources/config/event_listeners.yaml index be8b844b5cf..b0a58aaeebb 100644 --- a/bundles/CoreBundle/Resources/config/event_listeners.yaml +++ b/bundles/CoreBundle/Resources/config/event_listeners.yaml @@ -147,3 +147,5 @@ services: $debugToolbarListener: '@?web_profiler.debug_toolbar' Pimcore\Bundle\CoreBundle\EventListener\MessengerClearRuntimeCacheListener: ~ + + Pimcore\Bundle\CoreBundle\EventListener\AssetSanitizationListener: ~ \ No newline at end of file diff --git a/composer.json b/composer.json index c38263cd8b3..f7afbd8a9db 100644 --- a/composer.json +++ b/composer.json @@ -59,6 +59,7 @@ "symfony/doctrine-messenger": "^5.2.0", "egulias/email-validator": "^3.0.0", "endroid/qr-code": "^4", + "enshrined/svg-sanitize": "^0.14.1", "friendsofsymfony/jsrouting-bundle": "^2.7", "geoip2/geoip2": "^2.9", "google/apiclient": "^2.10",