diff --git a/README.md b/README.md index 6fb624d1..2a4d9d5d 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ To report bugs use [engelsystem/issues](https://github.com/engelsystem/engelsyst * Recommended: Directory Listing should be disabled. * There must a be MySQL database created with a user who has full rights to that database. * If necessary, create a ```config/config.php``` to override values from ```config/config.default.php```. - * To remove values from the `footer_items`, `available_themes`, `locales` or `tshirt_sizes` lists the config file has to be renamed. + * To remove values from the `footer_items`, `available_themes`, `locales`, `tshirt_sizes` or `headers` lists the config file has to be renamed. * To import the database the ```bin/migrate``` script has to be called. * In the browser, login with credentials ```admin```:```asdfasdf``` and change the password. diff --git a/config/app.php b/config/app.php index 77b1e874..7ba3509e 100644 --- a/config/app.php +++ b/config/app.php @@ -37,6 +37,7 @@ return [ // Changes of request/response parameters \Engelsystem\Middleware\SetLocale::class, + \Engelsystem\Middleware\AddHeaders::class, // The application code \Engelsystem\Middleware\ErrorHandler::class, diff --git a/config/config.default.php b/config/config.default.php index 879aa836..4ba6cdc1 100644 --- a/config/config.default.php +++ b/config/config.default.php @@ -150,4 +150,17 @@ return [ // IP addresses of reverse proxies that are trusted, can be an array or a comma separated list 'trusted_proxies' => env('TRUSTED_PROXIES', ['127.0.0.0/8', '::ffff:127.0.0.0/8', '::1/128']), + + // Add additional headers + 'add_headers' => (bool)env('ADD_HEADERS', true), + 'headers' => [ + 'X-Content-Type-Options' => 'nosniff', + 'X-Frame-Options' => 'sameorigin', + 'Referrer-Policy' => 'strict-origin-when-cross-origin', + 'Content-Security-Policy' => 'default-src \'self\' \'unsafe-inline\' \'unsafe-eval\'', + 'X-XSS-Protection' => '1; mode=block', + 'Feature-Policy' => 'autoplay \'none\'', + //'Strict-Transport-Security' => 'max-age=7776000', + //'Expect-CT' => 'max-age=7776000,enforce,report-uri="[uri]"', + ], ]; diff --git a/src/Middleware/AddHeaders.php b/src/Middleware/AddHeaders.php new file mode 100644 index 00000000..75383a90 --- /dev/null +++ b/src/Middleware/AddHeaders.php @@ -0,0 +1,46 @@ +config = $config; + } + + /** + * Process an incoming server request and setting the locale if required + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $response = $handler->handle($request); + if (!$this->config->get('add_headers', true)) { + return $response; + } + + $headers = $this->config->get('headers', []); + + foreach ($headers as $name => $value) { + $response = $response->withAddedHeader($name, $value); + } + + return $response; + } +} diff --git a/tests/Unit/Middleware/AddHeadersTest.php b/tests/Unit/Middleware/AddHeadersTest.php new file mode 100644 index 00000000..1a1a9e71 --- /dev/null +++ b/tests/Unit/Middleware/AddHeadersTest.php @@ -0,0 +1,43 @@ +getMockForAbstractClass(ServerRequestInterface::class); + /** @var RequestHandlerInterface|MockObject $handler */ + $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); + $response = new Response(); + + $handler->expects($this->atLeastOnce()) + ->method('handle') + ->willReturn($response); + + $config = new Config(['add_headers' => false]); + + $middleware = new AddHeaders($config); + $this->assertEquals($response, $middleware->process($request, $handler)); + + $config->set('add_headers', true); + $config->set('headers', ['Foo-Header' => 'bar!']); + $return = $middleware->process($request, $handler); + + $this->assertNotEquals($response, $return); + $this->assertArraySubset(['Foo-Header' => ['bar!']], $return->getHeaders()); + } +}