Forráskód Böngészése

Fix R01-N25: X-Permitted-Cross-Domain-Policies: none

Adobe Flash and Acrobat are dead, but the cross-domain-policies header
is a single-line, defence-in-depth lockout against any tooling that
still inspects the file. Added to the FatalErrorHandler::securityHeaders
single source of truth so both the happy path and the 500 fallback get
it for free, on HTTP and HTTPS alike. FatalErrorHandlerTest gains the
drift fence (header in the production-500 emit + present in the helper
on both HTTPS and plain HTTP).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chiappa 2 napja
szülő
commit
f6ce13f5c7
2 módosított fájl, 16 hozzáadás és 4 törlés
  1. 10 4
      src/Http/FatalErrorHandler.php
  2. 6 0
      tests/Http/FatalErrorHandlerTest.php

+ 10 - 4
src/Http/FatalErrorHandler.php

@@ -169,10 +169,16 @@ final class FatalErrorHandler
     public static function securityHeaders(bool $isHttps): array
     {
         $h = [
-            'X-Content-Type-Options'  => 'nosniff',
-            'X-Frame-Options'         => 'DENY',
-            'Referrer-Policy'         => 'strict-origin-when-cross-origin',
-            'Content-Security-Policy' => self::CSP,
+            'X-Content-Type-Options'              => 'nosniff',
+            'X-Frame-Options'                     => 'DENY',
+            'Referrer-Policy'                     => 'strict-origin-when-cross-origin',
+            // R01-N25: defence-in-depth for legacy Adobe Flash / Acrobat
+            // cross-origin policy lookups. Cheap header; tells those clients
+            // (and any tooling that still inspects the file) that no
+            // crossdomain.xml / clientaccesspolicy.xml is honoured under this
+            // origin.
+            'X-Permitted-Cross-Domain-Policies'   => 'none',
+            'Content-Security-Policy'             => self::CSP,
         ];
         if ($isHttps) {
             $h['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains';

+ 6 - 0
tests/Http/FatalErrorHandlerTest.php

@@ -50,6 +50,8 @@ final class FatalErrorHandlerTest extends TestCase
         self::assertContains('X-Content-Type-Options: nosniff', $this->headers);
         self::assertContains('X-Frame-Options: DENY', $this->headers);
         self::assertContains('Referrer-Policy: strict-origin-when-cross-origin', $this->headers);
+        // R01-N25: Flash / Acrobat cross-domain policy lockout.
+        self::assertContains('X-Permitted-Cross-Domain-Policies: none', $this->headers);
         self::assertContains(
             'Strict-Transport-Security: max-age=31536000; includeSubDomains',
             $this->headers,
@@ -196,11 +198,15 @@ final class FatalErrorHandlerTest extends TestCase
         self::assertSame('nosniff',                                $h['X-Content-Type-Options']);
         self::assertSame('DENY',                                   $h['X-Frame-Options']);
         self::assertSame('strict-origin-when-cross-origin',        $h['Referrer-Policy']);
+        self::assertSame('none',                                   $h['X-Permitted-Cross-Domain-Policies']);
         self::assertSame('max-age=31536000; includeSubDomains',    $h['Strict-Transport-Security']);
         self::assertArrayHasKey('Content-Security-Policy', $h);
 
         $hPlain = FatalErrorHandler::securityHeaders(false);
         self::assertArrayNotHasKey('Strict-Transport-Security', $hPlain);
+        // R01-N25: the new header is unconditional — must ride along on
+        // both HTTP and HTTPS responses, unlike HSTS.
+        self::assertSame('none', $hPlain['X-Permitted-Cross-Domain-Policies']);
     }
 
     /** @return callable(string,bool):void */