diff --git a/core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php b/core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php index f1477eac85b..0ed426dc0f1 100644 --- a/core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php +++ b/core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php @@ -133,6 +133,8 @@ class JsCollectionOptimizerLazy implements AssetCollectionGroupOptimizerInterfac 'scope' => $js_asset['scope'] === 'header' ? 'header' : 'footer', 'delta' => "$order", ] + $query_args; + // Add a filename prefix to mitigate ad blockers which can block + // any script beginning with 'ad'. $filename = 'js_' . $this->generateHash($js_asset) . '.js'; $uri = 'assets://js/' . $filename; $js_assets[$order]['data'] = $this->fileUrlGenerator->generateString($uri) . '?' . UrlHelper::buildQuery($query); diff --git a/core/modules/system/src/Controller/AssetControllerBase.php b/core/modules/system/src/Controller/AssetControllerBase.php index e9a91c07ea6..620b2ecccf7 100644 --- a/core/modules/system/src/Controller/AssetControllerBase.php +++ b/core/modules/system/src/Controller/AssetControllerBase.php @@ -136,6 +136,10 @@ abstract class AssetControllerBase extends FileDownloadController { throw new BadRequestHttpException('The libraries to include must be passed as a query argument'); } $file_parts = explode('_', basename($file_name, '.' . $this->fileExtension), 2); + // Ensure the filename is correctly prefixed. + if ($file_parts[0] !== $this->fileExtension) { + throw new BadRequestHttpException('The filename prefix must match the file extension'); + } // The hash is the second segment of the filename. if (!isset($file_parts[1])) { diff --git a/core/tests/Drupal/FunctionalTests/Asset/AssetOptimizationTest.php b/core/tests/Drupal/FunctionalTests/Asset/AssetOptimizationTest.php index 47bdd8ab081..d4c6021b80f 100644 --- a/core/tests/Drupal/FunctionalTests/Asset/AssetOptimizationTest.php +++ b/core/tests/Drupal/FunctionalTests/Asset/AssetOptimizationTest.php @@ -163,6 +163,9 @@ class AssetOptimizationTest extends BrowserTestBase { $session->visit($this->invalidExclude($url)); $this->assertSession()->statusCodeEquals(400); + $session->visit($this->replaceFileNamePrefix($url)); + $this->assertSession()->statusCodeEquals(400); + $session->visit($this->setInvalidLibrary($url)); $this->assertSession()->statusCodeEquals(200); @@ -210,6 +213,19 @@ class AssetOptimizationTest extends BrowserTestBase { return $this->getAbsoluteUrl(implode('_', $parts)); } + /** + * Replaces the filename prefix in the given URL. + * + * @param string $url + * The source URL. + * + * @return string + * The URL with the file name prefix replaced. + */ + protected function replaceFileNamePrefix(string $url): string { + return str_replace(['/css_', '/js_'], '/xyz_', $url); + } + /** * Replaces the 'include' entry in the given URL with an invalid value. *