Skip to content

Commit 0483281

Browse files
committed
feat: add support for more CSP3 directives
1 parent 6905da3 commit 0483281

File tree

5 files changed

+197
-6
lines changed

5 files changed

+197
-6
lines changed

app/Config/ContentSecurityPolicy.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,15 @@ class ContentSecurityPolicy extends BaseConfig
6161
*
6262
* @var list<string>|string
6363
*/
64-
public $scriptSrcElem = 'self';
64+
public array|string $scriptSrcElem = 'self';
65+
66+
/**
67+
* Specifies valid sources for JavaScript inline event
68+
* handlers and JavaScript URLs.
69+
*
70+
* @var list<string>|string
71+
*/
72+
public array|string $scriptSrcAttr = 'self';
6573

6674
/**
6775
* Lists allowed stylesheets' URLs.
@@ -70,6 +78,21 @@ class ContentSecurityPolicy extends BaseConfig
7078
*/
7179
public $styleSrc = 'self';
7280

81+
/**
82+
* Specifies valid sources for stylesheets <link> elements.
83+
*
84+
* @var list<string>|string
85+
*/
86+
public array|string $styleSrcElem = 'self';
87+
88+
/**
89+
* Specifies valid sources for stylesheets inline
90+
* style attributes and `<style>` elements.
91+
*
92+
* @var list<string>|string
93+
*/
94+
public array|string $styleSrcAttr = 'self';
95+
7396
/**
7497
* Defines the origins from which images can be loaded.
7598
*
@@ -152,6 +175,11 @@ class ContentSecurityPolicy extends BaseConfig
152175
*/
153176
public $manifestSrc;
154177

178+
/**
179+
* @var list<string>|string
180+
*/
181+
public array|string $workerSrc = [];
182+
155183
/**
156184
* Limits the kinds of plugins a page may invoke.
157185
*

system/HTTP/ContentSecurityPolicy.php

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ class ContentSecurityPolicy
4646
'sandbox' => 'sandbox',
4747
'manifest-src' => 'manifestSrc',
4848
'script-src-elem' => 'scriptSrcElem',
49+
'script-src-attr' => 'scriptSrcAttr',
50+
'style-src-elem' => 'styleSrcElem',
51+
'style-src-attr' => 'styleSrcAttr',
52+
'worker-src' => 'workerSrc',
4953
];
5054

5155
/**
@@ -191,7 +195,38 @@ class ContentSecurityPolicy
191195
*
192196
* @var array<string, bool>|string
193197
*/
194-
protected $scriptSrcElem = [];
198+
protected array|string $scriptSrcElem = [];
199+
200+
/**
201+
* The `script-src-attr` directive applies to event handlers and, if present,
202+
* it will override the `script-src` directive for relevant checks.
203+
*
204+
* @var array<string, bool>|string
205+
*/
206+
protected array|string $scriptSrcAttr = [];
207+
208+
/**
209+
* The `style-src-elem` directive governs the behaviour of styles except
210+
* for styles defined in inline attributes.
211+
*
212+
* @var array<string, bool>|string
213+
*/
214+
protected array|string $styleSrcElem = [];
215+
216+
/**
217+
* The `style-src-attr` directive governs the behaviour of style attributes.
218+
*
219+
* @var array<string, bool>|string
220+
*/
221+
protected array|string $styleSrcAttr = [];
222+
223+
/**
224+
* The `worker-src` directive restricts the URLs which may be loaded as a `Worker`,
225+
* `SharedWorker`, or `ServiceWorker`.
226+
*
227+
* @var array<string, bool>|string
228+
*/
229+
protected array|string $workerSrc = [];
195230

196231
/**
197232
* Instructs user agents to rewrite URL schemes by changing HTTP to HTTPS.
@@ -678,16 +713,28 @@ public function addScriptSrc($uri, ?bool $explicitReporting = null)
678713
* @see https://www.w3.org/TR/CSP/#directive-script-src-elem
679714
*
680715
* @param list<string>|string $uri
681-
*
682-
* @return $this
683716
*/
684-
public function addScriptSrcElem($uri, ?bool $explicitReporting = null)
717+
public function addScriptSrcElem(array|string $uri, ?bool $explicitReporting = null): static
685718
{
686719
$this->addOption($uri, 'scriptSrcElem', $explicitReporting ?? $this->reportOnly);
687720

688721
return $this;
689722
}
690723

724+
/**
725+
* Adds a new value to the `script-src-attr` directive.
726+
*
727+
* @see https://www.w3.org/TR/CSP/#directive-script-src-attr
728+
*
729+
* @param list<string>|string $uri
730+
*/
731+
public function addScriptSrcAttr(array|string $uri, ?bool $explicitReporting = null): static
732+
{
733+
$this->addOption($uri, 'scriptSrcAttr', $explicitReporting ?? $this->reportOnly);
734+
735+
return $this;
736+
}
737+
691738
/**
692739
* Adds a new value to the `style-src` directive.
693740
*
@@ -704,6 +751,48 @@ public function addStyleSrc($uri, ?bool $explicitReporting = null)
704751
return $this;
705752
}
706753

754+
/**
755+
* Adds a new value to the `style-src-elem` directive.
756+
*
757+
* @see https://www.w3.org/TR/CSP/#directive-style-src-elem
758+
*
759+
* @param list<string>|string $uri
760+
*/
761+
public function addStyleSrcElem(array|string $uri, ?bool $explicitReporting = null): static
762+
{
763+
$this->addOption($uri, 'styleSrcElem', $explicitReporting ?? $this->reportOnly);
764+
765+
return $this;
766+
}
767+
768+
/**
769+
* Adds a new value to the `style-src-attr` directive.
770+
*
771+
* @see https://www.w3.org/TR/CSP/#directive-style-src-attr
772+
*
773+
* @param list<string>|string $uri
774+
*/
775+
public function addStyleSrcAttr(array|string $uri, ?bool $explicitReporting = null): static
776+
{
777+
$this->addOption($uri, 'styleSrcAttr', $explicitReporting ?? $this->reportOnly);
778+
779+
return $this;
780+
}
781+
782+
/**
783+
* Adds a new value to the `worker-src` directive.
784+
*
785+
* @see https://www.w3.org/TR/CSP/#directive-worker-src
786+
*
787+
* @param list<string>|string $uri
788+
*/
789+
public function addWorkerSrc($uri, ?bool $explicitReporting = null): static
790+
{
791+
$this->addOption($uri, 'workerSrc', $explicitReporting ?? $this->reportOnly);
792+
793+
return $this;
794+
}
795+
707796
/**
708797
* Sets whether the user agents should rewrite URL schemes, changing HTTP to HTTPS.
709798
*

tests/system/HTTP/ContentSecurityPolicyTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,23 @@ public function testScriptSrcElem(): void
433433
$this->assertContains("script-src-elem 'self' cdn.cloudy.com", $this->getCspDirectives($header));
434434
}
435435

436+
#[PreserveGlobalState(false)]
437+
#[RunInSeparateProcess]
438+
public function testScriptSrcAttr(): void
439+
{
440+
$this->csp->addScriptSrcAttr('cdn.cloudy.com');
441+
$this->csp->addScriptSrcAttr('them.com', true);
442+
$this->assertTrue($this->work());
443+
444+
$header = $this->getHeaderEmitted('Content-Security-Policy-Report-Only');
445+
$this->assertIsString($header);
446+
$this->assertContains('script-src-attr them.com', $this->getCspDirectives($header));
447+
448+
$header = $this->getHeaderEmitted('Content-Security-Policy');
449+
$this->assertIsString($header);
450+
$this->assertContains("script-src-attr 'self' cdn.cloudy.com", $this->getCspDirectives($header));
451+
}
452+
436453
#[PreserveGlobalState(false)]
437454
#[RunInSeparateProcess]
438455
public function testStyleSrc(): void
@@ -450,6 +467,52 @@ public function testStyleSrc(): void
450467
$this->assertContains("style-src 'self' cdn.cloudy.com", $this->getCspDirectives($header));
451468
}
452469

470+
#[PreserveGlobalState(false)]
471+
#[RunInSeparateProcess]
472+
public function testStyleSrcElem(): void
473+
{
474+
$this->csp->addStyleSrcElem('cdn.cloudy.com');
475+
$this->csp->addStyleSrcElem('them.com', true);
476+
$this->assertTrue($this->work());
477+
478+
$header = $this->getHeaderEmitted('Content-Security-Policy-Report-Only');
479+
$this->assertIsString($header);
480+
$this->assertContains('style-src-elem them.com', $this->getCspDirectives($header));
481+
482+
$header = $this->getHeaderEmitted('Content-Security-Policy');
483+
$this->assertIsString($header);
484+
$this->assertContains("style-src-elem 'self' cdn.cloudy.com", $this->getCspDirectives($header));
485+
}
486+
487+
#[PreserveGlobalState(false)]
488+
#[RunInSeparateProcess]
489+
public function testStyleSrcAttr(): void
490+
{
491+
$this->csp->addStyleSrcAttr('cdn.cloudy.com');
492+
$this->csp->addStyleSrcAttr('them.com', true);
493+
$this->assertTrue($this->work());
494+
495+
$header = $this->getHeaderEmitted('Content-Security-Policy-Report-Only');
496+
$this->assertIsString($header);
497+
$this->assertContains('style-src-attr them.com', $this->getCspDirectives($header));
498+
499+
$header = $this->getHeaderEmitted('Content-Security-Policy');
500+
$this->assertIsString($header);
501+
$this->assertContains("style-src-attr 'self' cdn.cloudy.com", $this->getCspDirectives($header));
502+
}
503+
504+
#[PreserveGlobalState(false)]
505+
#[RunInSeparateProcess]
506+
public function testWorkerSrc(): void
507+
{
508+
$this->csp->addWorkerSrc('workers.com');
509+
$this->assertTrue($this->work());
510+
511+
$header = $this->getHeaderEmitted('Content-Security-Policy');
512+
$this->assertIsString($header);
513+
$this->assertContains('worker-src workers.com', $this->getCspDirectives($header));
514+
}
515+
453516
#[PreserveGlobalState(false)]
454517
#[RunInSeparateProcess]
455518
public function testBaseURIDefault(): void

user_guide_src/source/changelogs/v4.7.0.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,12 @@ Content Security Policy
340340

341341
- Added support for the following CSP Level 3 directives:
342342
- ``script-src-elem``
343+
- ``script-src-attr``
344+
- ``style-src-elem``
345+
- ``style-src-attr``
346+
- ``worker-src``
343347

344-
Update your CSP configuration in **app/Config/ContentSecurityPolicy.php** to include these new directives as needed.
348+
Update your CSP configuration in **app/Config/ContentSecurityPolicy.php** to include these new directives.
345349

346350
Others
347351
======

user_guide_src/source/outgoing/csp/012.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,10 @@
3131
$csp->addScriptSrc('scripts.example.com', true); // allow but report requests from here
3232
$csp->addStyleSrc('css.example.com');
3333
$csp->addSandbox(['allow-forms', 'allow-scripts']);
34+
35+
// the following CSP3 directives are available in v4.7.0 and later
36+
$csp->addScriptSrcAttr('trusted.com');
37+
$csp->addScriptSrcElem('trusted.com');
38+
$csp->addStyleSrcAttr('trusted.com');
39+
$csp->addStyleSrcElem('trusted.com');
40+
$csp->addWorkerSrc('workers.example.com');

0 commit comments

Comments
 (0)