Phase1 Bearbeitung
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
final class SecurityHeadersService
|
||||
{
|
||||
public function buildHeaders(?bool $isHttps = null): array
|
||||
{
|
||||
$isHttps = $isHttps ?? $this->isHttpsRequest();
|
||||
|
||||
$headers = [
|
||||
'Content-Security-Policy' => $this->buildContentSecurityPolicy($isHttps),
|
||||
'Referrer-Policy' => 'strict-origin-when-cross-origin',
|
||||
'Permissions-Policy' => 'accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()',
|
||||
'Cross-Origin-Opener-Policy' => 'same-origin',
|
||||
'Cross-Origin-Resource-Policy' => 'same-origin',
|
||||
'Origin-Agent-Cluster' => '?1',
|
||||
'X-Content-Type-Options' => 'nosniff',
|
||||
'X-Frame-Options' => 'SAMEORIGIN',
|
||||
'X-Permitted-Cross-Domain-Policies' => 'none',
|
||||
];
|
||||
|
||||
if ($isHttps) {
|
||||
$headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains';
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
public function send(array $overrides = [], ?bool $isHttps = null): void
|
||||
{
|
||||
if (headers_sent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$headers = $this->buildHeaders($isHttps);
|
||||
|
||||
foreach ($overrides as $name => $value) {
|
||||
if (!is_string($name) || trim($name) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value === null) {
|
||||
unset($headers[$name]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$headers[$name] = (string) $value;
|
||||
}
|
||||
|
||||
header_remove('X-Powered-By');
|
||||
|
||||
foreach ($headers as $name => $value) {
|
||||
header($name . ': ' . $value, true);
|
||||
}
|
||||
}
|
||||
|
||||
private function buildContentSecurityPolicy(bool $isHttps): string
|
||||
{
|
||||
$directives = [
|
||||
"default-src 'self'",
|
||||
"base-uri 'self'",
|
||||
"form-action 'self'",
|
||||
"frame-ancestors 'self'",
|
||||
"object-src 'none'",
|
||||
"connect-src 'self'",
|
||||
"font-src 'self' data:",
|
||||
"img-src 'self' data:",
|
||||
"manifest-src 'self'",
|
||||
"script-src 'self'",
|
||||
"style-src 'self'",
|
||||
];
|
||||
|
||||
if ($isHttps) {
|
||||
$directives[] = 'upgrade-insecure-requests';
|
||||
}
|
||||
|
||||
return implode('; ', $directives);
|
||||
}
|
||||
|
||||
private function isHttpsRequest(): bool
|
||||
{
|
||||
$https = $_SERVER['HTTPS'] ?? null;
|
||||
|
||||
if (is_string($https) && $https !== '' && strtolower($https) !== 'off') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$forwardedProto = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '';
|
||||
|
||||
if (is_string($forwardedProto) && strtolower($forwardedProto) === 'https') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (string) ($_SERVER['SERVER_PORT'] ?? '') === '443';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user