Skip to content

Commit 8f15b3f

Browse files
committed
Make CSP header code more readable
Signed-off-by: Maximilian Krög <maxi_kroeg@web.de>
1 parent 2522b36 commit 8f15b3f

2 files changed

Lines changed: 78 additions & 83 deletions

File tree

src/Header.php

Lines changed: 62 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222

2323
use function array_merge;
2424
use function htmlspecialchars;
25+
use function implode;
2526
use function ini_get;
2627
use function json_encode;
27-
use function sprintf;
2828

2929
use 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

tests/unit/HeaderTest.php

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,14 @@ public function testGetHttpHeaders(
199199
$config->set('CaptchaCsp', $captchaCsp);
200200

201201
$expected = [
202-
'X-Frame-Options' => $expectedFrameOptions ?? '',
203202
'Referrer-Policy' => 'same-origin',
204203
'Content-Security-Policy' => $expectedCsp,
205204
'X-XSS-Protection' => '1; mode=block',
206205
'X-Content-Type-Options' => 'nosniff',
207206
'X-Permitted-Cross-Domain-Policies' => 'none',
208207
'X-Robots-Tag' => 'noindex, nofollow',
209208
'Permissions-Policy' => 'fullscreen=(self), interest-cohort=()',
209+
'X-Frame-Options' => $expectedFrameOptions ?? '',
210210
'Expires' => 'Wed, 21 Oct 2015 07:28:00 GMT',
211211
'Cache-Control' => 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0',
212212
'Pragma' => 'no-cache',
@@ -231,9 +231,11 @@ public static function providerForTestGetHttpHeaders(): array
231231
'',
232232
'',
233233
'DENY',
234-
'default-src \'self\' ;script-src \'self\' \'unsafe-inline\' \'unsafe-eval\' ;'
235-
. 'style-src \'self\' \'unsafe-inline\' ;img-src \'self\' data: tile.openstreetmap.org;'
236-
. 'object-src \'none\';',
234+
"default-src 'self';"
235+
. " img-src 'self' data: tile.openstreetmap.org;"
236+
. " object-src 'none';"
237+
. " script-src 'self' 'unsafe-inline' 'unsafe-eval';"
238+
. " style-src 'self' 'unsafe-inline';"
237239
],
238240
[
239241
'sameorigin',
@@ -242,12 +244,11 @@ public static function providerForTestGetHttpHeaders(): array
242244
'PublicKey',
243245
'captcha.tld csp.tld',
244246
'SAMEORIGIN',
245-
'default-src \'self\' captcha.tld csp.tld example.com example.net;'
246-
. 'script-src \'self\' \'unsafe-inline\' \'unsafe-eval\' '
247-
. 'captcha.tld csp.tld example.com example.net;'
248-
. 'style-src \'self\' \'unsafe-inline\' captcha.tld csp.tld example.com example.net;'
249-
. 'img-src \'self\' data: example.com example.net tile.openstreetmap.org captcha.tld csp.tld ;'
250-
. 'object-src \'none\';',
247+
"default-src 'self' captcha.tld csp.tld example.com example.net;"
248+
. " img-src 'self' data: captcha.tld csp.tld example.com example.net tile.openstreetmap.org;"
249+
. " object-src 'none';"
250+
. " script-src 'self' 'unsafe-inline' 'unsafe-eval' captcha.tld csp.tld example.com example.net;"
251+
. " style-src 'self' 'unsafe-inline' captcha.tld csp.tld example.com example.net;"
251252
],
252253
[
253254
true,
@@ -256,10 +257,11 @@ public static function providerForTestGetHttpHeaders(): array
256257
'PublicKey',
257258
'captcha.tld csp.tld',
258259
null,
259-
'default-src \'self\' captcha.tld csp.tld ;'
260-
. 'script-src \'self\' \'unsafe-inline\' \'unsafe-eval\' captcha.tld csp.tld ;'
261-
. 'style-src \'self\' \'unsafe-inline\' captcha.tld csp.tld ;'
262-
. 'img-src \'self\' data: tile.openstreetmap.org captcha.tld csp.tld ;object-src \'none\';',
260+
"default-src 'self' captcha.tld csp.tld;"
261+
. " img-src 'self' data: captcha.tld csp.tld tile.openstreetmap.org;"
262+
. " object-src 'none';"
263+
. " script-src 'self' 'unsafe-inline' 'unsafe-eval' captcha.tld csp.tld;"
264+
. " style-src 'self' 'unsafe-inline' captcha.tld csp.tld;",
263265
],
264266
];
265267
}

0 commit comments

Comments
 (0)