From 67da71c761789e720c137f60f501dc966d22fc6f Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Mon, 13 Feb 2023 13:53:21 +0100 Subject: [PATCH 1/2] Partially address Turbo-related CSP errors --- assets/bootstrap.js | 11 ++++ config/packages/nelmio_security.yaml | 1 + config/services.yaml | 4 ++ .../ContentSecurityPolicy/NonceGenerator.php | 51 +++++++++++++++++++ templates/base.html.twig | 14 +++++ 5 files changed, 81 insertions(+) create mode 100644 src/Infrastructure/Security/ContentSecurityPolicy/NonceGenerator.php diff --git a/assets/bootstrap.js b/assets/bootstrap.js index 4ab2df643..2f80be76b 100644 --- a/assets/bootstrap.js +++ b/assets/bootstrap.js @@ -1,3 +1,4 @@ +import * as _Turbo from '@hotwired/turbo'; import { startStimulusApp } from '@symfony/stimulus-bridge'; // Registers Stimulus controllers from controllers.json and in the controllers/ directory @@ -9,3 +10,13 @@ export const app = startStimulusApp(require.context( // register any custom, 3rd party controllers here // app.register('some_controller_name', SomeImportedController); + +// See: https://github.com/hotwired/turbo/issues/294#issuecomment-877842232 +document.addEventListener('turbo:before-fetch-request', (event) => { + event.detail.fetchOptions.headers['X-CSP-Nonce'] = document.querySelector('meta[name="csp-nonce"]').content; +}); +document.addEventListener('turbo:before-cache', () => { + document.querySelectorAll('script[nonce]').forEach((element) => { + element.setAttribute('nonce', element.nonce); + }); +}); diff --git a/config/packages/nelmio_security.yaml b/config/packages/nelmio_security.yaml index 057101cfc..f51a11c5b 100644 --- a/config/packages/nelmio_security.yaml +++ b/config/packages/nelmio_security.yaml @@ -29,6 +29,7 @@ nelmio_security: csp: enabled: true enforce: + level1_fallback: true default-src: ['self'] script-src: ['self'] style-src: ['self'] diff --git a/config/services.yaml b/config/services.yaml index 86fad94c5..bf6bc407b 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -64,6 +64,10 @@ services: DateTimeInterface: class: DateTimeImmutable + App\Infrastructure\Security\ContentSecurityPolicy\NonceGenerator: + decorates: 'nelmio_security.nonce_generator' + arguments: ['@.inner'] + when@test: services: App\Tests\Mock\APIAdresseMockClient: diff --git a/src/Infrastructure/Security/ContentSecurityPolicy/NonceGenerator.php b/src/Infrastructure/Security/ContentSecurityPolicy/NonceGenerator.php new file mode 100644 index 000000000..9b792ab80 --- /dev/null +++ b/src/Infrastructure/Security/ContentSecurityPolicy/NonceGenerator.php @@ -0,0 +1,51 @@ +requestNonce) { + return $this->requestNonce; + } else { + return $this->parent->generate(); + } + } + + public static function getSubscribedEvents(): array + { + return [ + KernelEvents::REQUEST => ['onKernelRequest', 400], + KernelEvents::RESPONSE => 'onKernelResponse', + ]; + } + + public function onKernelRequest(RequestEvent $event): void + { + if ($event->getRequest()->headers->has('X-CSP-Nonce')) { + $this->requestNonce = $event->getRequest()->headers->get('X-CSP-Nonce'); + } + } + + public function onKernelResponse(ResponseEvent $event): void + { + $this->requestNonce = null; + } +} diff --git a/templates/base.html.twig b/templates/base.html.twig index a96288787..085e4eace 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -4,6 +4,20 @@ + + {# + Turbo manipulates the DOM by inserting elements, stylesheets, and scripts. + So we need to grant it a nonce to pass the Content-Security-Policy. + We suppress CSP errors on initial page load thanks to the following double-call + to csp_nonce(), some Turbo configuration to send the nonce along with Turbo Drive + requests, and the custom NonceGenerator which reuses the nonce in the CSP header. + But page navigations may still generate CSP errors. + See: https://github.com/nelmio/NelmioSecurityBundle/issues/321 + #} + {% set _nonce = csp_nonce('script') %} + {% set _nonce = csp_nonce('style') %} + + From f5c654ad5f69f9c9f9157807db7dfd83b0afc0d9 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Thu, 23 Feb 2023 16:53:47 +0100 Subject: [PATCH 2/2] Simplify --- assets/bootstrap.js | 11 ---- config/packages/nelmio_security.yaml | 1 - config/services.yaml | 4 -- .../ContentSecurityPolicy/NonceGenerator.php | 51 ------------------- templates/base.html.twig | 10 ---- 5 files changed, 77 deletions(-) delete mode 100644 src/Infrastructure/Security/ContentSecurityPolicy/NonceGenerator.php diff --git a/assets/bootstrap.js b/assets/bootstrap.js index 2f80be76b..4ab2df643 100644 --- a/assets/bootstrap.js +++ b/assets/bootstrap.js @@ -1,4 +1,3 @@ -import * as _Turbo from '@hotwired/turbo'; import { startStimulusApp } from '@symfony/stimulus-bridge'; // Registers Stimulus controllers from controllers.json and in the controllers/ directory @@ -10,13 +9,3 @@ export const app = startStimulusApp(require.context( // register any custom, 3rd party controllers here // app.register('some_controller_name', SomeImportedController); - -// See: https://github.com/hotwired/turbo/issues/294#issuecomment-877842232 -document.addEventListener('turbo:before-fetch-request', (event) => { - event.detail.fetchOptions.headers['X-CSP-Nonce'] = document.querySelector('meta[name="csp-nonce"]').content; -}); -document.addEventListener('turbo:before-cache', () => { - document.querySelectorAll('script[nonce]').forEach((element) => { - element.setAttribute('nonce', element.nonce); - }); -}); diff --git a/config/packages/nelmio_security.yaml b/config/packages/nelmio_security.yaml index f51a11c5b..057101cfc 100644 --- a/config/packages/nelmio_security.yaml +++ b/config/packages/nelmio_security.yaml @@ -29,7 +29,6 @@ nelmio_security: csp: enabled: true enforce: - level1_fallback: true default-src: ['self'] script-src: ['self'] style-src: ['self'] diff --git a/config/services.yaml b/config/services.yaml index bf6bc407b..86fad94c5 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -64,10 +64,6 @@ services: DateTimeInterface: class: DateTimeImmutable - App\Infrastructure\Security\ContentSecurityPolicy\NonceGenerator: - decorates: 'nelmio_security.nonce_generator' - arguments: ['@.inner'] - when@test: services: App\Tests\Mock\APIAdresseMockClient: diff --git a/src/Infrastructure/Security/ContentSecurityPolicy/NonceGenerator.php b/src/Infrastructure/Security/ContentSecurityPolicy/NonceGenerator.php deleted file mode 100644 index 9b792ab80..000000000 --- a/src/Infrastructure/Security/ContentSecurityPolicy/NonceGenerator.php +++ /dev/null @@ -1,51 +0,0 @@ -requestNonce) { - return $this->requestNonce; - } else { - return $this->parent->generate(); - } - } - - public static function getSubscribedEvents(): array - { - return [ - KernelEvents::REQUEST => ['onKernelRequest', 400], - KernelEvents::RESPONSE => 'onKernelResponse', - ]; - } - - public function onKernelRequest(RequestEvent $event): void - { - if ($event->getRequest()->headers->has('X-CSP-Nonce')) { - $this->requestNonce = $event->getRequest()->headers->get('X-CSP-Nonce'); - } - } - - public function onKernelResponse(ResponseEvent $event): void - { - $this->requestNonce = null; - } -} diff --git a/templates/base.html.twig b/templates/base.html.twig index 085e4eace..9542c4502 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -4,16 +4,6 @@ - - {# - Turbo manipulates the DOM by inserting elements, stylesheets, and scripts. - So we need to grant it a nonce to pass the Content-Security-Policy. - We suppress CSP errors on initial page load thanks to the following double-call - to csp_nonce(), some Turbo configuration to send the nonce along with Turbo Drive - requests, and the custom NonceGenerator which reuses the nonce in the CSP header. - But page navigations may still generate CSP errors. - See: https://github.com/nelmio/NelmioSecurityBundle/issues/321 - #} {% set _nonce = csp_nonce('script') %} {% set _nonce = csp_nonce('style') %}