ignition
ignition copied to clipboard
Blocked by CSP package
We are using https://github.com/spatie/laravel-csp on our app, which is causing ignition to display a blank page with the following console error.
Refused to execute inline script because it violates the following Content Security Policy directive
This seems to happen because the <script>
and <style>
tags injected by the Ignition package don't use csp_nonce()
.
I can confirm that adding nonce="<?= csp_nonce(); ?>"
to various places in https://github.com/spatie/ignition/blob/main/resources/views/errorPage.php got the error page displaying, although still a few wonky bits to chase down
I wonder if there's a simpler way to disable CSP for Ignition error pages
Hi @liamkeily, thanks for reporting this! At first glance it seems like the CSP package is a bit too eager adding CSP headers to Ignition responses... I'm gonna leave this open for anyone else coming across this issue (and if anyone wants to submit a PR to either spatie/laravel-csp or this package, feel free!).
I ended up solving this (and some other things) by extending https://github.com/spatie/laravel-csp/blob/main/src/Policies/Policy.php and implementing the following method
public function shouldBeApplied(Request $request, Response $response): bool
{
if (config('app.debug') && (
$response->isClientError() || // Ignition
$response->isServerError() || // Ignition
Vite::isRunningHot() || // Vite
(config('telescope.enabled') && str_starts_with($request->path(), 'telescope')) // Telescope
)) {
return false;
}
return parent::shouldBeApplied($request, $response);
}
Perhaps there's a better approach but it did the job
Dear contributor,
because this issue seems to be inactive for quite some time now, I've automatically closed it. If you feel this issue deserves some attention from my human colleagues feel free to reopen it.
I wish to re-open this hoping to find a better solution.
I ended up adding another middleware to take care of nonce in every inline scripts tags in the errorPage.php. This will only be triggered when a response received either isClientError() or isServerError().
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class AddNonceToInlineScripts
{
public function handle($request, Closure $next)
{
$response = $next($request);
if ($response->isClientError() || $response->isServerError()) {
$content = $response->getContent();
$nonce = csp_nonce();
$contentWithNonce = $this->addNonceToInlineScripts($content, $nonce);
$response->setContent($contentWithNonce);
}
return $response;
}
protected function addNonceToInlineScripts($content, $nonce)
{
return preg_replace_callback('/<script(.*?)>(.*?)<\/script>/is', function ($match) use ($nonce) {
$attributes = $match[1];
$scriptContent = $match[2];
if (!str_contains($attributes, 'nonce')) {
$attributes .= " nonce=\"$nonce\"";
}
return "<script$attributes>$scriptContent</script>";
}, $content);
}
}
Using a single nonce value for all script tags within a page is possible and is a valid approach to adhere to a Content Security Policy (CSP). In CSP, the nonce attribute is used to specify which scripts are allowed to execute based on a matching nonce value. If you use the same nonce attribute for all script tags, the CSP will consider them all as trusted and allow them to execute.
In this code, I can only generate one nonce value using csp_nonce() function (even calling it multiple times). Overall, it still works...
You can apply the same approach for inline style.
Hope it helps!
Here is the change that integrates ignition
with csp
package - https://github.com/spatie/ignition/pull/462.
an other temporary solution would be to bind Spatie\Ignition\Ignition
class to a custom implementation via Laravel service container. Implementation should override renderException()
method in order to use blade renderer so nonce="{{csp_nonce()}}"
can be used on script/styles tags (make sure to create a blade template mimicking the one being used by ignition).
// in AppServiceProvider.php
public function register() {
$this->app->bind(\Spatie\Ignition\Ignition::class, \App\YourCustomIgnition::class);
}
// in YourCustomIgnition.php
public function renderException(Throwable $throwable, ?Report $report = null): void
{
$this->setUpFlare();
$report ??= $this->createReport($throwable);
$viewModel = new ErrorPageViewModel(
$throwable,
$this->ignitionConfig,
$report,
$this->solutionProviderRepository->getSolutionsForThrowable($throwable),
$this->solutionTransformerClass,
$this->customHtmlHead,
$this->customHtmlBody,
);
echo view('your.custom.template', ['viewModel' => $viewModel])->render();
// or simply include your php file here utilizing $viewModel variable
// include resource_path('your.custom.template');
}
I stopped with another one temporarily (the method of Spatie\Csp\Policies\Policy
):
public function shouldBeApplied(Request $request, Response $response): bool
{
if ((
parent::shouldBeApplied($request, $response)
&& !$this->app->environment('testing')
&& !$request->isXmlHttpRequest()
)) {
// @todo PSSPP1-1793: Remove this processing when resolved.
// https://github.com/spatie/ignition/pull/462
if ((
$response->isServerError()
&& ($content = $response->getContent())
&& \str_contains($content, '<script')
)) {
$response->setContent(
\preg_replace(
'/(<script)(.+?>)/usm',
"$1 nonce='".\csp_nonce()."'$2",
$content,
),
);
}
return true;
}
return false;
}
Hi @freekmurze why is it closed ? is there any solutions inside ignition ? or there should be used workarounds like https://github.com/spatie/ignition/issues/186#issuecomment-1888466267