Skip to content

Commit

Permalink
Partially address Turbo-related CSP errors
Browse files Browse the repository at this point in the history
  • Loading branch information
florimondmanca committed Feb 23, 2023
1 parent cd29274 commit 67da71c
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 0 deletions.
11 changes: 11 additions & 0 deletions assets/bootstrap.js
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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);
});
});
1 change: 1 addition & 0 deletions config/packages/nelmio_security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ nelmio_security:
csp:
enabled: true
enforce:
level1_fallback: true
default-src: ['self']
script-src: ['self']
style-src: ['self']
Expand Down
4 changes: 4 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace App\Infrastructure\Security\ContentSecurityPolicy;

use Nelmio\SecurityBundle\ContentSecurityPolicy\NonceGenerator as ParentNonceGenerator;
use Nelmio\SecurityBundle\ContentSecurityPolicy\NonceGeneratorInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

class NonceGenerator implements NonceGeneratorInterface, EventSubscriberInterface
{
private ?string $requestNonce = null;

public function __construct(
private readonly ParentNonceGenerator $parent,
) {
}

public function generate(): string
{
if ($this->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;
}
}
14 changes: 14 additions & 0 deletions templates/base.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

{#
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') %}
<meta name="csp-nonce" content="{{ _nonce }}">

<link rel="apple-touch-icon" href="{{ asset('build/dsfr/favicon/apple-touch-icon.png') }}"><!-- 180×180 -->
<link rel="icon" href="{{ asset('build/dsfr/favicon/favicon.svg') }}" type="image/svg+xml">
<link rel="shortcut icon" href="{{ asset('build/dsfr/favicon/favicon.ico') }}" type="image/x-icon"><!-- 32×32 -->
Expand Down

0 comments on commit 67da71c

Please sign in to comment.