vendor/shopware/core/Framework/Routing/CoreSubscriber.php line 45

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Routing;
  3. use Shopware\Core\Framework\Log\Package;
  4. use Shopware\Core\Framework\Routing\Annotation\RouteScope as RouteScopeAnnotation;
  5. use Shopware\Core\PlatformRequest;
  6. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  7. use Symfony\Component\HttpKernel\Event\RequestEvent;
  8. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  9. use Symfony\Component\HttpKernel\KernelEvents;
  10. /**
  11. * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0
  12. */
  13. #[Package('core')]
  14. class CoreSubscriber implements EventSubscriberInterface
  15. {
  16. /**
  17. * @var array<string>
  18. */
  19. private array $cspTemplates;
  20. /**
  21. * @internal
  22. *
  23. * @param array<string> $cspTemplates
  24. */
  25. public function __construct(array $cspTemplates)
  26. {
  27. $this->cspTemplates = $cspTemplates;
  28. }
  29. /**
  30. * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  31. */
  32. public static function getSubscribedEvents()
  33. {
  34. return [
  35. KernelEvents::REQUEST => 'initializeCspNonce',
  36. KernelEvents::RESPONSE => 'setSecurityHeaders',
  37. ];
  38. }
  39. public function initializeCspNonce(RequestEvent $event): void
  40. {
  41. $nonce = base64_encode(random_bytes(8));
  42. $event->getRequest()->attributes->set(PlatformRequest::ATTRIBUTE_CSP_NONCE, $nonce);
  43. }
  44. public function setSecurityHeaders(ResponseEvent $event): void
  45. {
  46. if (!$event->getResponse()->isSuccessful()) {
  47. return;
  48. }
  49. $response = $event->getResponse();
  50. if ($event->getRequest()->isSecure()) {
  51. $response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  52. }
  53. $response->headers->set('X-Frame-Options', 'deny');
  54. $response->headers->set('X-Content-Type-Options', 'nosniff');
  55. $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
  56. $cspTemplate = $this->cspTemplates['default'] ?? '';
  57. $scopes = $event->getRequest()->attributes->get(PlatformRequest::ATTRIBUTE_ROUTE_SCOPE, []);
  58. if ($scopes instanceof RouteScopeAnnotation) {
  59. $scopes = $scopes->getScopes();
  60. }
  61. foreach ($scopes as $scope) {
  62. $cspTemplate = $this->cspTemplates[$scope] ?? $cspTemplate;
  63. }
  64. $cspTemplate = trim($cspTemplate);
  65. if ($cspTemplate !== '' && !$response->headers->has('Content-Security-Policy')) {
  66. $nonce = $event->getRequest()->attributes->get(PlatformRequest::ATTRIBUTE_CSP_NONCE);
  67. if (\is_string($nonce)) {
  68. $csp = str_replace('%nonce%', $nonce, $cspTemplate);
  69. $csp = str_replace(["\n", "\r"], ' ', $csp);
  70. $response->headers->set('Content-Security-Policy', $csp);
  71. }
  72. }
  73. }
  74. }