xref: /webtrees/app/Http/Middleware/SecurityHeaders.php (revision f5f6ea63614b81411b0fd17559583ba4fa68d8a7)
19c88b4e9SGreg Roach<?php
29c88b4e9SGreg Roach
39c88b4e9SGreg Roach/**
49c88b4e9SGreg Roach * webtrees: online genealogy
5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team
69c88b4e9SGreg Roach * This program is free software: you can redistribute it and/or modify
79c88b4e9SGreg Roach * it under the terms of the GNU General Public License as published by
89c88b4e9SGreg Roach * the Free Software Foundation, either version 3 of the License, or
99c88b4e9SGreg Roach * (at your option) any later version.
109c88b4e9SGreg Roach * This program is distributed in the hope that it will be useful,
119c88b4e9SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
129c88b4e9SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
139c88b4e9SGreg Roach * GNU General Public License for more details.
149c88b4e9SGreg Roach * You should have received a copy of the GNU General Public License
1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>.
169c88b4e9SGreg Roach */
179c88b4e9SGreg Roach
189c88b4e9SGreg Roachdeclare(strict_types=1);
199c88b4e9SGreg Roach
209c88b4e9SGreg Roachnamespace Fisharebest\Webtrees\Http\Middleware;
219c88b4e9SGreg Roach
22*f5f6ea63SGreg Roachuse Fisharebest\Webtrees\Validator;
239c88b4e9SGreg Roachuse Psr\Http\Message\ResponseInterface;
249c88b4e9SGreg Roachuse Psr\Http\Message\ServerRequestInterface;
259c88b4e9SGreg Roachuse Psr\Http\Server\MiddlewareInterface;
269c88b4e9SGreg Roachuse Psr\Http\Server\RequestHandlerInterface;
279c88b4e9SGreg Roach
289c88b4e9SGreg Roach/**
299c88b4e9SGreg Roach * Middleware to set security-related HTTP headers.
309c88b4e9SGreg Roach */
319c88b4e9SGreg Roachclass SecurityHeaders implements MiddlewareInterface
329c88b4e9SGreg Roach{
339c88b4e9SGreg Roach    private const SECURITY_HEADERS = [
34a9e82893SGreg Roach        'Permissions-Policy'     => 'browsing-topics=()',
359c88b4e9SGreg Roach        'Referrer-Policy'        => 'same-origin',
369c88b4e9SGreg Roach        'X-Content-Type-Options' => 'nosniff',
379c88b4e9SGreg Roach        'X-Frame-Options'        => 'SAMEORIGIN',
389c88b4e9SGreg Roach        'X-XSS-Protection'       => '1; mode=block',
399c88b4e9SGreg Roach    ];
409c88b4e9SGreg Roach
419c88b4e9SGreg Roach    /**
429c88b4e9SGreg Roach     * @param ServerRequestInterface  $request
439c88b4e9SGreg Roach     * @param RequestHandlerInterface $handler
449c88b4e9SGreg Roach     *
459c88b4e9SGreg Roach     * @return ResponseInterface
469c88b4e9SGreg Roach     */
479c88b4e9SGreg Roach    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
489c88b4e9SGreg Roach    {
499c88b4e9SGreg Roach        $response = $handler->handle($request);
509c88b4e9SGreg Roach
519c88b4e9SGreg Roach        foreach (self::SECURITY_HEADERS as $header_name => $header_value) {
529c88b4e9SGreg Roach            // Don't overwrite existing headers.
539c88b4e9SGreg Roach            if ($response->getHeader($header_name) === []) {
549c88b4e9SGreg Roach                $response = $response->withHeader($header_name, $header_value);
559c88b4e9SGreg Roach            }
569c88b4e9SGreg Roach        }
579c88b4e9SGreg Roach
58*f5f6ea63SGreg Roach        $base_url = Validator::attributes($request)->string('base_url');
59*f5f6ea63SGreg Roach
60*f5f6ea63SGreg Roach        if (str_starts_with($base_url, 'https://') && $response->getHeader('Strict-Transport-Security') === []) {
61*f5f6ea63SGreg Roach            $response = $response->withHeader('Strict-Transport-Security', 'max-age=31536000');
62*f5f6ea63SGreg Roach        }
63*f5f6ea63SGreg Roach
649c88b4e9SGreg Roach        return $response;
659c88b4e9SGreg Roach    }
669c88b4e9SGreg Roach}
67