diff --git a/apps/settings/lib/SetupChecks/SecurityHeaders.php b/apps/settings/lib/SetupChecks/SecurityHeaders.php index ec4b7a5cc09b0..09f8b09b331aa 100644 --- a/apps/settings/lib/SetupChecks/SecurityHeaders.php +++ b/apps/settings/lib/SetupChecks/SecurityHeaders.php @@ -53,6 +53,13 @@ public function run(): SetupResult { 'X-Permitted-Cross-Domain-Policies' => ['none', null], ]; + // Normalize header values + $normalize = static function (string $value): string { + $values = array_map('trim', explode(',', strtolower($value))); + sort($values); + return implode(',', $values); + }; + foreach ($urls as [$verb,$url,$validStatuses]) { $works = null; foreach ($this->runRequest($verb, $url, ['httpErrors' => false]) as $response) { @@ -64,13 +71,21 @@ public function run(): SetupResult { $msg = ''; $msgParameters = []; foreach ($securityHeaders as $header => [$expected, $accepted]) { - /* Convert to lowercase and remove spaces after comas */ - $value = preg_replace('/,\s+/', ',', strtolower($response->getHeader($header))); - if ($value !== $expected) { - if ($accepted !== null && $value === $accepted) { - $msg .= $this->l10n->t('- The `%1$s` HTTP header is not set to `%2$s`. Some features might not work correctly, as it is recommended to adjust this setting accordingly.', [$header, $expected]) . "\n"; + $normalizedValue = $normalize($response->getHeader($header)); + $normalizedExpected = $normalize($expected); + $normalizedAccepted = $accepted !== null ? $normalize($accepted) : null; + + if ($normalizedValue !== $normalizedExpected) { + if ($normalizedAccepted !== null && $normalizedValue === $normalizedAccepted) { + $msg .= $this->l10n->t( + '- The `%1$s` HTTP header is not set to `%2$s`. Some features might not work correctly, as it is recommended to adjust this setting accordingly.', + [$header, $expected] + ) . "\n"; } else { - $msg .= $this->l10n->t('- The `%1$s` HTTP header is not set to `%2$s`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.', [$header, $expected]) . "\n"; + $msg .= $this->l10n->t( + '- The `%1$s` HTTP header is not set to `%2$s`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.', + [$header, $expected] + ) . "\n"; } } } diff --git a/apps/settings/tests/SetupChecks/SecurityHeadersTest.php b/apps/settings/tests/SetupChecks/SecurityHeadersTest.php index 7dc4dd970dbb4..9a7a606cff048 100644 --- a/apps/settings/tests/SetupChecks/SecurityHeadersTest.php +++ b/apps/settings/tests/SetupChecks/SecurityHeadersTest.php @@ -96,6 +96,7 @@ public static function dataSuccess(): array { // description => modifiedHeaders 'basic' => [[]], 'no-space-in-x-robots' => [['X-Robots-Tag' => 'noindex,nofollow']], + 'reordered-x-robots' => [['X-Robots-Tag' => 'nofollow, noindex']], 'strict-origin-when-cross-origin' => [['Referrer-Policy' => 'strict-origin-when-cross-origin']], 'referrer-no-referrer-when-downgrade' => [['Referrer-Policy' => 'no-referrer-when-downgrade']], 'referrer-strict-origin' => [['Referrer-Policy' => 'strict-origin']], @@ -137,6 +138,7 @@ public static function dataFailure(): array { return [ // description => modifiedHeaders 'x-robots-none' => [['X-Robots-Tag' => 'none'], "- The `X-Robots-Tag` HTTP header is not set to `noindex,nofollow`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.\n"], + 'x-robots-additional-directive' => [['X-Robots-Tag' => 'noindex,nofollow,noarchive'], "- The `X-Robots-Tag` HTTP header is not set to `noindex,nofollow`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.\n"], 'referrer-origin' => [['Referrer-Policy' => 'origin'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"], 'referrer-origin-when-cross-origin' => [['Referrer-Policy' => 'origin-when-cross-origin'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"], 'referrer-unsafe-url' => [['Referrer-Policy' => 'unsafe-url'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"],