default-src|script-src|style-src|object-src)\h+(?[^;]+)(?:\s*;\s*|$)#'; /** * @var ContentSecurityPolicyDirective[] */ protected $directives = []; public function __construct(string $header) { if (preg_match_all(self::HEADER_PATTERN, $header, $matches)) { foreach ($matches['directive'] as $index => $name) { $this->directives[$name] = new ContentSecurityPolicyDirective( $name, $matches['rule'][$index] ); } } } public function isEmpty(): bool { return empty($this->directives); } public function mitigatesCrossSiteScripting(?string $fileName = null): bool { $isSvg = str_ends_with($fileName ?? '', '.svg'); $defaultSrc = isset($this->directives['default-src']) ? $this->directiveMitigatesCrossSiteScripting($this->directives['default-src']) : null; $scriptSrc = isset($this->directives['script-src']) ? $this->directiveMitigatesCrossSiteScripting($this->directives['script-src']) : null; $styleSrc = isset($this->directives['style-src']) ? $this->directiveMitigatesCrossSiteScripting($this->directives['style-src']) || ($isSvg && $this->directives['style-src']->hasInstructions('unsafe-inline')) : null; $objectSrc = isset($this->directives['object-src']) ? $this->directiveMitigatesCrossSiteScripting($this->directives['object-src']) : null; return ($scriptSrc ?? $defaultSrc ?? false) && ($styleSrc ?? $defaultSrc ?? false) && ($objectSrc ?? $defaultSrc ?? false); } protected function directiveMitigatesCrossSiteScripting(ContentSecurityPolicyDirective $directive): bool { return $directive->hasInstructions('none') && !$directive->hasInstructions('unsafe-eval', 'unsafe-inline'); } }