laravel / horizon

Dashboard and code-driven configuration for Laravel queues.
https://laravel.com/docs/horizon
MIT License
3.82k stars 636 forks source link

Error: Subresource Integrity: The resource styles.css has an integrity attribute... #1436

Closed jhm-ciberman closed 2 months ago

jhm-ciberman commented 2 months ago

Horizon Version

v5.24.3

Laravel Version

11.x

PHP Version

8.3

Redis Driver

PhpRedis

Redis Version

-

Database Driver & Version

-

Description

Brief

If you configure your ASSET_URL: (https://laravel.com/docs/11.x/vite#custom-base-urls)

ASSET_URL=https://cdn.example.com

Then the Horizon CSS won't load at all:

Chrome Dev Console:

Subresource Integrity: The resource 'https://cdn.example.com/vendor/horizon/styles.css' has an integrity attribute, but the resource requires the request to be CORS enabled to check the integrity, and it is not. The resource has been blocked because the integrity cannot be enforced.
Subresource Integrity: The resource 'https://cdn.example.com/vendor/horizon/styles-dark.css' has an integrity attribute, but the resource requires the request to be CORS enabled to check the integrity, and it is not. The resource has been blocked because the integrity cannot be enforced.

Description of the bug

The problem relies in that Horizon uses a new instance of \Illuminate\Foundation\Vite for injecting the CSS and javascript:

$viteDataSchemeLight = new ViteFoundation();
$viteDataSchemeLight->useHotFile($nonExistentFileName);
$viteDataSchemeLight->useStyleTagAttributes([
'data-scheme' => 'light',
]);

The problem, is that this generates a tag like this:

<link rel="preload" as="style" href="https://cdn.example.com/vendor/horizon/styles.css" integrity="sha384-4HOmv1E51xgqbUYzCYXaRXPRja5nEho6eq/L/CKs0LlidzTGNTk81VtCAHqLiYSC" />
<link rel="stylesheet" href="https://cdn.example.com/vendor/horizon/styles.css" integrity="sha384-4HOmv1E51xgqbUYzCYXaRXPRja5nEho6eq/L/CKs0LlidzTGNTk81VtCAHqLiYSC" data-scheme="light" />

In order for the browser to check the data integrity and use the integrity tag:

  1. The CDN (or Url where the CSS file is hosted) must send the CORS headers (Access-Control-Allow-Origin: *). ✅
  2. The crossorigin attribute must be defined in the <link> tag and set to anonymous. ❌

How To Fix

Simply add 'crossorigin' => 'anonymous' to both tags:

$viteDataSchemeDark = new ViteFoundation();
$viteDataSchemeDark->useHotFile($nonExistentFileName);
$viteDataSchemeDark->useStyleTagAttributes([
'data-scheme' => 'dark',
+ 'crossorigin' => 'anonymous',
]);

Steps To Reproduce

  1. Configure your ASSET_URL to point to a CDN:
ASSET_URL=https://cdn.example.com

Ensure the CDN is sending the proper CORS headers.

  1. Open Horizon. The CSS won't load.
jhm-ciberman commented 2 months ago

Looks like a duplicate of https://github.com/laravel/horizon/issues/1425

Closing and waiting for the next release.

jhm-ciberman commented 2 months ago

@driesvints is this fixed in master? Currently the Horizon UI is unusable for me in production.