Skip to content

Commit e417dfb

Browse files
author
Oleksandr Gorkun
committed
MC-30971: CSP policies must be defined in a single header
1 parent d0f4142 commit e417dfb

File tree

4 files changed

+24
-16
lines changed

4 files changed

+24
-16
lines changed

app/code/Magento/Csp/Model/Policy/Renderer/SimplePolicyHeaderRenderer.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public function render(PolicyInterface $policy, HttpResponse $response): void
4545
$header = 'Content-Security-Policy';
4646
}
4747
$value = $policy->getId() .' ' .$policy->getValue() .';';
48-
if ($config->getReportUri()) {
48+
if ($config->getReportUri() && !$response->getHeader('Report-To')) {
4949
$reportToData = [
5050
'group' => 'report-endpoint',
5151
'max_age' => 10886400,
@@ -57,7 +57,10 @@ public function render(PolicyInterface $policy, HttpResponse $response): void
5757
$value .= ' report-to '. $reportToData['group'] .';';
5858
$response->setHeader('Report-To', json_encode($reportToData), true);
5959
}
60-
$response->setHeader($header, $value, false);
60+
if ($existing = $response->getHeader($header)) {
61+
$value = $existing->getFieldValue() .' ' .$value;
62+
}
63+
$response->setHeader($header, $value, true);
6164
}
6265

6366
/**

dev/tests/integration/testsuite/Magento/Csp/CspAwareActionTest.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,13 @@ public function testAwareAction(): void
3131
{
3232
$this->getRequest()->setMethod('GET');
3333
$this->dispatch('csputil/csp/aware');
34-
$headers = '';
35-
foreach ($this->getResponse()->getHeaders() as $header) {
36-
$headers .= $header->getFieldName() .': ' .$header->getFieldValue() .PHP_EOL;
37-
}
34+
$header = $this->getResponse()->getHeader('Content-Security-Policy');
35+
$this->assertNotEmpty($header);
3836

3937
$this->assertContains(
40-
'Content-Security-Policy: script-src https://controller.magento.com'
38+
'script-src https://controller.magento.com'
4139
.' \'self\' \'sha256-H4RRnauTM2X2Xg/z9zkno1crqhsaY3uKKu97uwmnXXE=\'',
42-
$headers
40+
$header->getFieldValue()
4341
);
4442
}
4543
}

dev/tests/integration/testsuite/Magento/Csp/CspUtilTest.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class CspUtilTest extends AbstractController
2020
* Test that CSP helper for templates works.
2121
*
2222
* @return void
23+
* @magentoConfigFixture default_store csp/mode/storefront/report_only 0
2324
*/
2425
public function testPhtmlHelper(): void
2526
{
@@ -29,11 +30,9 @@ public function testPhtmlHelper(): void
2930

3031
$this->assertContains('<script src="http://my.magento.com/static/script.js" />', $content);
3132
$this->assertContains("<script>\n let myVar = 1;\n</script>", $content);
32-
$headers = '';
33-
foreach ($this->getResponse()->getHeaders() as $header) {
34-
$headers .= $header->getFieldName() .': ' .$header->getFieldValue() .PHP_EOL;
35-
}
36-
$this->assertContains('http://my.magento.com', $headers);
37-
$this->assertContains('\'sha256-H4RRnauTM2X2Xg/z9zkno1crqhsaY3uKKu97uwmnXXE=\'', $headers);
33+
$header = $this->getResponse()->getHeader('Content-Security-Policy');
34+
$this->assertNotEmpty($header);
35+
$this->assertContains('http://my.magento.com', $header->getFieldValue());
36+
$this->assertContains('\'sha256-H4RRnauTM2X2Xg/z9zkno1crqhsaY3uKKu97uwmnXXE=\'', $header->getFieldValue());
3837
}
3938
}

lib/internal/Magento/Framework/HTTP/PhpEnvironment/Response.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ public function getHeader($name)
2828
$headers = $this->getHeaders();
2929
if ($headers->has($name)) {
3030
$header = $headers->get($name);
31+
if (is_iterable($header)) {
32+
$header = $header[0];
33+
}
3134
}
3235
return $header;
3336
}
@@ -94,8 +97,13 @@ public function clearHeader($name)
9497
{
9598
$headers = $this->getHeaders();
9699
if ($headers->has($name)) {
97-
$header = $headers->get($name);
98-
$headers->removeHeader($header);
100+
$headerValues = $headers->get($name);
101+
if (!is_iterable($headerValues)) {
102+
$headerValues = [$headerValues];
103+
}
104+
foreach ($headerValues as $headerValue) {
105+
$headers->removeHeader($headerValue);
106+
}
99107
}
100108

101109
return $this;

0 commit comments

Comments
 (0)