Files
clinicpro/src/Shared/EventSubscriber/AdminCspSubscriber.php
T

51 lines
1.5 KiB
PHP

<?php
namespace App\Shared\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Adds a Content-Security-Policy to the admin SPA responses (/admin/*).
* The /api/* surface already sends `default-src 'none'`; the SPA had none, so a
* DOM-injected script had no second line of defence. Scoped to /admin only to
* avoid breaking the strict API CSP.
*/
final class AdminCspSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [KernelEvents::RESPONSE => 'onResponse'];
}
public function onResponse(ResponseEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
if (!str_starts_with($event->getRequest()->getPathInfo(), '/admin')) {
return;
}
$response = $event->getResponse();
if ($response->headers->has('Content-Security-Policy')) {
return;
}
$response->headers->set(
'Content-Security-Policy',
"default-src 'self'; "
. "script-src 'self'; "
. "style-src 'self' 'unsafe-inline'; " // Tailwind / CKEditor inline styles
. "img-src 'self' data: blob:; "
. "font-src 'self' data:; "
. "connect-src 'self'; "
. "frame-ancestors 'none'; "
. "base-uri 'self'; "
. "object-src 'none'"
);
}
}