2222
2323use function array_merge ;
2424use function htmlspecialchars ;
25+ use function implode ;
2526use function ini_get ;
2627use function json_encode ;
27- use function sprintf ;
2828
2929use const JSON_HEX_TAG ;
3030
@@ -332,7 +332,49 @@ public function getMessage(): string
332332 /** @return array<string, string> */
333333 public function getHttpHeaders (ClockInterface |null $ clock = null ): array
334334 {
335- $ headers = [];
335+ $ headers = [
336+ 'Referrer-Policy ' => 'same-origin ' ,
337+
338+ 'Content-Security-Policy ' => $ this ->getCspHeader (),
339+
340+ /**
341+ * Re-enable possible disabled XSS filters.
342+ *
343+ * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-XSS-Protection
344+ */
345+ 'X-XSS-Protection ' => '1; mode=block ' ,
346+
347+ /**
348+ * "nosniff", prevents Internet Explorer and Google Chrome from MIME-sniffing
349+ * a response away from the declared content-type.
350+ *
351+ * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Content-Type-Options
352+ */
353+ 'X-Content-Type-Options ' => 'nosniff ' ,
354+
355+ /**
356+ * Adobe cross-domain-policies.
357+ *
358+ * @see https://www.sentrium.co.uk/labs/application-security-101-http-headers
359+ */
360+ 'X-Permitted-Cross-Domain-Policies ' => 'none ' ,
361+
362+ /**
363+ * Robots meta tag.
364+ *
365+ * @see https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag
366+ */
367+ 'X-Robots-Tag ' => 'noindex, nofollow ' ,
368+
369+ /**
370+ * The HTTP Permissions-Policy header provides a mechanism to allow and deny
371+ * the use of browser features in a document
372+ * or within any <iframe> elements in the document.
373+ *
374+ * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/Permissions-Policy
375+ */
376+ 'Permissions-Policy ' => 'fullscreen=(self), interest-cohort=() ' ,
377+ ];
336378
337379 /* Prevent against ClickJacking by disabling framing */
338380 if ($ this ->config ->config ->AllowThirdPartyFraming === 'sameorigin ' ) {
@@ -341,48 +383,6 @@ public function getHttpHeaders(ClockInterface|null $clock = null): array
341383 $ headers ['X-Frame-Options ' ] = 'DENY ' ;
342384 }
343385
344- $ headers ['Referrer-Policy ' ] = 'same-origin ' ;
345-
346- $ headers ['Content-Security-Policy ' ] = $ this ->getCspHeader ();
347-
348- /**
349- * Re-enable possible disabled XSS filters.
350- *
351- * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-XSS-Protection
352- */
353- $ headers ['X-XSS-Protection ' ] = '1; mode=block ' ;
354-
355- /**
356- * "nosniff", prevents Internet Explorer and Google Chrome from MIME-sniffing
357- * a response away from the declared content-type.
358- *
359- * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Content-Type-Options
360- */
361- $ headers ['X-Content-Type-Options ' ] = 'nosniff ' ;
362-
363- /**
364- * Adobe cross-domain-policies.
365- *
366- * @see https://www.sentrium.co.uk/labs/application-security-101-http-headers
367- */
368- $ headers ['X-Permitted-Cross-Domain-Policies ' ] = 'none ' ;
369-
370- /**
371- * Robots meta tag.
372- *
373- * @see https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag
374- */
375- $ headers ['X-Robots-Tag ' ] = 'noindex, nofollow ' ;
376-
377- /**
378- * The HTTP Permissions-Policy header provides a mechanism to allow and deny
379- * the use of browser features in a document
380- * or within any <iframe> elements in the document.
381- *
382- * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/Permissions-Policy
383- */
384- $ headers ['Permissions-Policy ' ] = 'fullscreen=(self), interest-cohort=() ' ;
385-
386386 $ headers = array_merge ($ headers , Core::getNoCacheHeaders ($ clock ?? new Clock ()));
387387
388388 /**
@@ -427,32 +427,25 @@ public function getPageTitle(): string
427427 private function getCspHeader (): string
428428 {
429429 $ mapTileUrl = ' tile.openstreetmap.org ' ;
430- $ captchaUrl = '' ;
431- $ cspAllow = $ this ->config ->config ->CSPAllow ;
432-
433- if (
434- $ this ->config ->config ->CaptchaLoginPrivateKey !== ''
435- && $ this ->config ->config ->CaptchaLoginPublicKey !== ''
436- && $ this ->config ->config ->CaptchaApi !== ''
437- && $ this ->config ->config ->CaptchaRequestParam !== ''
438- && $ this ->config ->config ->CaptchaResponseParam !== ''
439- ) {
440- $ captchaUrl = ' ' . $ this ->config ->config ->CaptchaCsp . ' ' ;
441- }
430+ $ cspAllow = $ this ->config ->config ->CSPAllow === '' ? '' : ' ' . $ this ->config ->config ->CSPAllow ;
431+ $ captchaUrl =
432+ $ this ->config ->config ->CaptchaLoginPrivateKey === '' ||
433+ $ this ->config ->config ->CaptchaLoginPublicKey === '' ||
434+ $ this ->config ->config ->CaptchaApi === '' ||
435+ $ this ->config ->config ->CaptchaRequestParam === '' ||
436+ $ this ->config ->config ->CaptchaResponseParam === ''
437+ ? ''
438+ : ' ' . $ this ->config ->config ->CaptchaCsp ;
439+
440+ $ csp = [
441+ "default-src 'self' " . $ captchaUrl . $ cspAllow ,
442+ "img-src 'self' data: " . $ captchaUrl . $ cspAllow . $ mapTileUrl ,
443+ "object-src 'none' " ,
444+ "script-src 'self' 'unsafe-inline' 'unsafe-eval' " . $ captchaUrl . $ cspAllow ,
445+ "style-src 'self' 'unsafe-inline' " . $ captchaUrl . $ cspAllow ,
446+ ];
442447
443- return sprintf (
444- 'default-src \'self \' %s%s;script-src \'self \' \'unsafe-inline \' \'unsafe-eval \' %s%s; '
445- . 'style-src \'self \' \'unsafe-inline \' %s%s;img-src \'self \' data: %s%s%s;object-src \'none \'; ' ,
446- $ captchaUrl ,
447- $ cspAllow ,
448- $ captchaUrl ,
449- $ cspAllow ,
450- $ captchaUrl ,
451- $ cspAllow ,
452- $ cspAllow ,
453- $ mapTileUrl ,
454- $ captchaUrl ,
455- );
448+ return implode ('; ' , $ csp ) . '; ' ;
456449 }
457450
458451 private function getVariablesForJavaScript (): string
0 commit comments