feat(security): add HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy headers

main
boban 2026-05-16 07:51:33 +02:00
parent e33a1fafde
commit 3f6b281c62
3 changed files with 33 additions and 0 deletions

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class SecurityHeaders
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-Frame-Options', 'DENY');
$response->headers->set('Referrer-Policy', 'strict-origin');
$response->headers->set('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');
return $response;
}
}

View File

@ -15,6 +15,7 @@ return Application::configure(basePath: dirname(__DIR__))
->withMiddleware(function (Middleware $middleware): void {
$middleware->web(append: [
\App\Http\Middleware\LocaleFromUser::class,
\App\Http\Middleware\SecurityHeaders::class,
]);
$middleware->validateCsrfTokens(except: [

View File

@ -0,0 +1,9 @@
<?php
it('sends HSTS header on all requests', function () {
$response = $this->get('/');
$response->assertHeader('Strict-Transport-Security');
$response->assertHeader('X-Content-Type-Options', 'nosniff');
$response->assertHeader('X-Frame-Options', 'DENY');
$response->assertHeader('Referrer-Policy', 'strict-origin');
});