fix(csp): add nonce to all inline style and script tags
Some checks are pending
Code Style / Laravel Pint (push) Waiting to run
Code Style / PHP CodeSniffer (push) Waiting to run
Static Analysis / PHPStan (push) Waiting to run
Static Analysis / Psalm (push) Waiting to run
Static Analysis / Security Audit (push) Waiting to run
Static Analysis / PHP Syntax Check (push) Waiting to run
Tests / PHP 8.2 - Laravel 11.* (push) Waiting to run
Tests / PHP 8.3 - Laravel 11.* (push) Waiting to run
Tests / PHP 8.4 - Laravel 11.* (push) Waiting to run
Tests / PHP 8.3 - Laravel 12.* (push) Waiting to run
Tests / PHP 8.4 - Laravel 12.* (push) Waiting to run
Some checks are pending
Code Style / Laravel Pint (push) Waiting to run
Code Style / PHP CodeSniffer (push) Waiting to run
Static Analysis / PHPStan (push) Waiting to run
Static Analysis / Psalm (push) Waiting to run
Static Analysis / Security Audit (push) Waiting to run
Static Analysis / PHP Syntax Check (push) Waiting to run
Tests / PHP 8.2 - Laravel 11.* (push) Waiting to run
Tests / PHP 8.3 - Laravel 11.* (push) Waiting to run
Tests / PHP 8.4 - Laravel 11.* (push) Waiting to run
Tests / PHP 8.3 - Laravel 12.* (push) Waiting to run
Tests / PHP 8.4 - Laravel 12.* (push) Waiting to run
Register CSP nonce with Vite::useCspNonce() so Livewire and Flux inherit it automatically. Add @cspnonce directive to all inline <style> and <script> blocks in layout templates to satisfy strict style-src/script-src CSP in production. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
feb47c8ea5
commit
4f09bfedd2
4 changed files with 16 additions and 7 deletions
|
|
@ -18,12 +18,12 @@
|
||||||
<title>{{ $title }}</title>
|
<title>{{ $title }}</title>
|
||||||
|
|
||||||
{{-- Critical CSS: Prevents white flash during page load/navigation --}}
|
{{-- Critical CSS: Prevents white flash during page load/navigation --}}
|
||||||
<style>
|
<style @cspnonce>
|
||||||
html { background-color: #f3f4f6; }
|
html { background-color: #f3f4f6; }
|
||||||
html.dark { background-color: #111827; }
|
html.dark { background-color: #111827; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script @cspnonce>
|
||||||
(function () {
|
(function () {
|
||||||
var darkMode = localStorage.getItem('dark-mode');
|
var darkMode = localStorage.getItem('dark-mode');
|
||||||
if (darkMode === 'true') {
|
if (darkMode === 'true') {
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
x-init="$watch('sidebarExpanded', value => localStorage.setItem('sidebar-expanded', value))"
|
x-init="$watch('sidebarExpanded', value => localStorage.setItem('sidebar-expanded', value))"
|
||||||
>
|
>
|
||||||
|
|
||||||
<script>
|
<script @cspnonce>
|
||||||
if (localStorage.getItem('sidebar-expanded') == 'true') {
|
if (localStorage.getItem('sidebar-expanded') == 'true') {
|
||||||
document.querySelector('body').classList.add('sidebar-expanded');
|
document.querySelector('body').classList.add('sidebar-expanded');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -91,7 +91,7 @@
|
||||||
|
|
||||||
{{ $scripts ?? '' }}
|
{{ $scripts ?? '' }}
|
||||||
|
|
||||||
<script>
|
<script @cspnonce>
|
||||||
// Light/Dark mode toggle (guarded for Livewire navigation)
|
// Light/Dark mode toggle (guarded for Livewire navigation)
|
||||||
(function() {
|
(function() {
|
||||||
if (window.__lightSwitchInitialized) return;
|
if (window.__lightSwitchInitialized) return;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{{-- Self-hosted Inter variable font --}}
|
{{-- Self-hosted Inter variable font --}}
|
||||||
<style>
|
<style @cspnonce>
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
src: url('/fonts/InterVariable.woff2') format('woff2-variations');
|
src: url('/fonts/InterVariable.woff2') format('woff2-variations');
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
<title>{{ $title }}</title>
|
<title>{{ $title }}</title>
|
||||||
|
|
||||||
{{-- Critical CSS: Prevents white flash during page load/navigation --}}
|
{{-- Critical CSS: Prevents white flash during page load/navigation --}}
|
||||||
<style>
|
<style @cspnonce>
|
||||||
html { background-color: #ffffff; }
|
html { background-color: #ffffff; }
|
||||||
html.dark { background-color: #111827; }
|
html.dark { background-color: #111827; }
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Core\Headers;
|
namespace Core\Headers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Vite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for generating and managing CSP nonces.
|
* Service for generating and managing CSP nonces.
|
||||||
*
|
*
|
||||||
|
|
@ -84,10 +86,17 @@ class CspNonceService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a cryptographically secure nonce.
|
* Generate a cryptographically secure nonce.
|
||||||
|
*
|
||||||
|
* Also registers it with Vite so Livewire and Vite-generated tags
|
||||||
|
* automatically include the nonce attribute.
|
||||||
*/
|
*/
|
||||||
protected function generateNonce(): string
|
protected function generateNonce(): string
|
||||||
{
|
{
|
||||||
return base64_encode(random_bytes($this->nonceLength));
|
$nonce = base64_encode(random_bytes($this->nonceLength));
|
||||||
|
|
||||||
|
Vite::useCspNonce($nonce);
|
||||||
|
|
||||||
|
return $nonce;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue