. */ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\Middleware; use Fisharebest\Webtrees\Validator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; /** * Middleware to set security-related HTTP headers. */ class SecurityHeaders implements MiddlewareInterface { private const SECURITY_HEADERS = [ 'Permissions-Policy' => 'browsing-topics=()', 'Referrer-Policy' => 'same-origin', 'X-Content-Type-Options' => 'nosniff', 'X-Frame-Options' => 'SAMEORIGIN', 'X-XSS-Protection' => '1; mode=block', ]; /** * @param ServerRequestInterface $request * @param RequestHandlerInterface $handler * * @return ResponseInterface */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $response = $handler->handle($request); foreach (self::SECURITY_HEADERS as $header_name => $header_value) { // Don't overwrite existing headers. if ($response->getHeader($header_name) === []) { $response = $response->withHeader($header_name, $header_value); } } $base_url = Validator::attributes($request)->string('base_url'); if (str_starts_with($base_url, 'https://') && $response->getHeader('Strict-Transport-Security') === []) { $response = $response->withHeader('Strict-Transport-Security', 'max-age=31536000'); } return $response; } }