From fcf83040db588911bee6251dd80feda2db1e26ae Mon Sep 17 00:00:00 2001 From: Kevin Adametz Date: Mon, 20 Jul 2026 15:47:13 +0000 Subject: [PATCH] web: www-Hosts leiten kanonisch per 301 auf die Apex-Domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ploi kann nur Pfad-Redirects, daher als App-Middleware (früh im globalen Stack): GET/HEAD auf www. → 301 auf die Apex-Domain mit Pfad und Query. Unsichere Methoden werden nicht umgeleitet (301 verwirft den Body) — die beantwortet die App dank Host-Normalisierung weiterhin selbst. Co-Authored-By: Claude Fable 5 --- app/Http/Middleware/RedirectWwwToApex.php | 37 +++++++++++++++++++++++ bootstrap/app.php | 6 ++++ tests/Feature/Web/WwwRedirectTest.php | 32 ++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 app/Http/Middleware/RedirectWwwToApex.php create mode 100644 tests/Feature/Web/WwwRedirectTest.php diff --git a/app/Http/Middleware/RedirectWwwToApex.php b/app/Http/Middleware/RedirectWwwToApex.php new file mode 100644 index 00000000..d72a5016 --- /dev/null +++ b/app/Http/Middleware/RedirectWwwToApex.php @@ -0,0 +1,37 @@ +getHost()); + + if (! str_starts_with($host, 'www.') || ! $request->isMethodSafe()) { + return $next($request); + } + + return redirect()->away( + $request->getScheme().'://'.substr($host, 4).$request->getRequestUri(), + 301 + ); + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index efd30e35..240c54e2 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -2,6 +2,7 @@ use App\Http\Middleware\BasicAuthMiddleware; use App\Http\Middleware\LogApiUsage; +use App\Http\Middleware\RedirectWwwToApex; use App\Http\Middleware\RejectLegacyApiKeys; use App\Http\Middleware\SecurityHeaders; use App\Http\Middleware\SetCurrentPortal; @@ -28,6 +29,11 @@ return Application::configure(basePath: dirname(__DIR__)) ) ->withMiddleware(function (Middleware $middleware) { + // Kanonische Hosts: www. → 301 auf die Apex-Domain, so früh + // wie möglich (vor Session/Theme), damit www-Requests gar nicht erst + // gerendert werden. + $middleware->prepend(RedirectWwwToApex::class); + // Security-Header auf allen Antworten (Web + API), Proxy-unabhängig. $middleware->append(SecurityHeaders::class); diff --git a/tests/Feature/Web/WwwRedirectTest.php b/tests/Feature/Web/WwwRedirectTest.php new file mode 100644 index 00000000..fa5af879 --- /dev/null +++ b/tests/Feature/Web/WwwRedirectTest.php @@ -0,0 +1,32 @@ +get('https://www.presseecho.test/de/impressum?foo=bar') + ->assertStatus(301) + ->assertRedirect('https://presseecho.test/de/impressum?foo=bar'); + + $this->get('https://www.businessportal24.test/de') + ->assertStatus(301) + ->assertRedirect('https://businessportal24.test/de'); +}); + +test('apex hosts are not redirected', function () { + /** @var TestCase $this */ + $this->get('https://presseecho.test/de/impressum')->assertSuccessful(); +}); + +test('unsafe methods on www hosts are answered instead of redirected', function () { + /** @var TestCase $this */ + // POST darf nicht 301en (Body ginge verloren) — die App beantwortet den + // Request dank Host-Normalisierung auch auf dem www-Host selbst. + $this->post('https://www.presseecho.test/de/kontakt') + ->assertStatus(302); // Validierungs-Redirect der Kontakt-Route, kein 301 +});