<?php
declare(strict_types=1);
namespace App\Subscriber;
use App\Store\StoreContext;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Setting various security headers
*
* @package App\Subscriber
*/
class SecurityHeaderSubscriber implements EventSubscriberInterface
{
private StoreContext $storeContext;
private LoggerInterface $logger;
public function __construct(StoreContext $storeContext, LoggerInterface $logger)
{
$this->storeContext = $storeContext;
$this->logger = $logger;
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents(): array
{
// run after EventListener\DisallowRobotsIndexingListener
return [KernelEvents::RESPONSE => ['onKernelResponse', -256]];
}
/**
* Conservative add headers (don't replace exiting ones)
*
* @param ResponseEvent $event
*
* @return void
*/
public function onKernelResponse(ResponseEvent $event): void
{
$headers = $event->getResponse()->headers;
// Instructs browser to not send referer when downgrading from https to http
if (!$headers->has('Referrer-Policy')) {
$headers->set('Referrer-Policy', 'strict-origin-when-cross-origin', false);
}
// Prevents browser from trying to guess the mime-type of a response.
// Reduces risk of execution of user uploaded content and exposure to drive-by downloads
if (!$headers->has('X-Content-Type-Options')) {
$headers->set('X-Content-Type-Options', 'nosniff', false);
}
// It would be better if Content-Security-Policy can be more strict. But that requires checking all used resources across the whole store
if ($event->getRequest()->isSecure() && !$headers->has('Content-Security-Policy')) { // if this request is not secure, it makes little sense to force an upgrade for all used resources
$headers->set('Content-Security-Policy', 'upgrade-insecure-requests', false);
}
// Use CSP to allow iframe embed for trusted resources (needed for SAP ARIBA integration)
if ($headers->has('X-Frame-Options')) {
$headers->remove('X-Frame-Options');
}
if ($this->storeContext->isPunchoutStore()) {
$headers->set('Content-Security-Policy', "frame-ancestors *", false);
} else {
$headers->set('Content-Security-Policy', "frame-ancestors 'self' app.storyblok.com", false);
}
// Disable something that is very unlikely to be used, just to add this header
if (!$headers->has('Feature-Policy')) {
$headers->set('Feature-Policy', 'usb \'none\'', false);
}
}
}