124 lines
3.3 KiB
PHP
Executable File
124 lines
3.3 KiB
PHP
Executable File
<?php
|
|
|
|
namespace common\components\SecureHeaders;
|
|
|
|
use hyperia\security\headers\PolicyInterface;
|
|
|
|
class ContentSecurityPolicy implements PolicyInterface
|
|
{
|
|
private $directives;
|
|
private $reportUri;
|
|
private $requireSriForScript;
|
|
private $requireSriForStyle;
|
|
private $blockAllMixedContent;
|
|
private $upgradeInsecureRequests;
|
|
private $defaultDirectives = [
|
|
'connect-src' => "'self'",
|
|
'font-src' => "'self'",
|
|
'frame-src' => "'self'",
|
|
'img-src' => "'self' data:",
|
|
'manifest-src' => "'self'",
|
|
'object-src' => "'self'",
|
|
'prefetch-src' => "'self'",
|
|
'script-src' => "'self' 'unsafe-inline'",
|
|
'style-src' => "'self' 'unsafe-inline'",
|
|
'media-src' => "'self'",
|
|
'form-action' => "'self'",
|
|
'worker-src' => "'self'",
|
|
];
|
|
|
|
private $defaultCsp = [
|
|
'default-src' => "*"
|
|
];
|
|
|
|
public function __construct(array $directives, array $params, string $reportUri)
|
|
{
|
|
$this->directives = $directives;
|
|
$this->reportUri = $reportUri;
|
|
$this->requireSriForScript = $params['requireSriForScript'] ?? false;
|
|
$this->requireSriForStyle = $params['requireSriForStyle'] ?? false;
|
|
$this->blockAllMixedContent = $params['blockAllMixedContent'] ?? false;
|
|
$this->upgradeInsecureRequests = $params['upgradeInsecureRequests'] ?? false;
|
|
}
|
|
|
|
public function getName(): string
|
|
{
|
|
return 'Content-Security-Policy';
|
|
}
|
|
|
|
public function getValue(): string
|
|
{
|
|
$result = '';
|
|
$cspDirectives = $this->buildPolicyArray();
|
|
|
|
foreach ($cspDirectives as $directive => $value) {
|
|
$result .= $directive . ' ' . $value . '; ';
|
|
}
|
|
|
|
if ($this->blockAllMixedContent) {
|
|
$result .= 'block-all-mixed-content; ';
|
|
}
|
|
|
|
if ($this->upgradeInsecureRequests) {
|
|
$result .= 'upgrade-insecure-requests; ';
|
|
}
|
|
|
|
return trim((string)$result, '; ');
|
|
}
|
|
|
|
public function isValid(): bool
|
|
{
|
|
$allowedDirectives = array_keys(array_merge($this->defaultCsp, $this->defaultDirectives));
|
|
foreach ($this->directives as $directive => $value) {
|
|
if (!in_array($directive, $allowedDirectives) && !empty($value)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private function getCspReportUri(): array
|
|
{
|
|
$report = [];
|
|
if (!empty($this->reportUri)) {
|
|
$report = [
|
|
'report-uri' => $this->reportUri . '/r/d/csp/enforce'
|
|
];
|
|
}
|
|
|
|
return $report;
|
|
}
|
|
|
|
private function getCspSubresourceIntegrity(): array
|
|
{
|
|
$result = [];
|
|
|
|
if ($this->requireSriForScript) {
|
|
$values[] = 'script';
|
|
}
|
|
|
|
if ($this->requireSriForStyle) {
|
|
$values[] = 'style';
|
|
}
|
|
|
|
if (!empty($values)) {
|
|
$result = [
|
|
'require-sri-for' => implode(' ', $values)
|
|
];
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
private function buildPolicyArray(): array
|
|
{
|
|
return array_merge(
|
|
$this->defaultCsp,
|
|
$this->defaultDirectives,
|
|
$this->directives,
|
|
$this->getCspSubresourceIntegrity(),
|
|
$this->getCspReportUri()
|
|
);
|
|
}
|
|
} |