Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add CSP clearDirective() to clear existing directive #8220

Merged
merged 6 commits into from
Nov 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 49 additions & 28 deletions system/HTTP/ContentSecurityPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,31 @@
*/
class ContentSecurityPolicy
{
/**
* CSP directives
*
* @var array<string, string>
*/
protected array $directives = [
'base-uri' => 'baseURI',
'child-src' => 'childSrc',
'connect-src' => 'connectSrc',
'default-src' => 'defaultSrc',
'font-src' => 'fontSrc',
'form-action' => 'formAction',
'frame-ancestors' => 'frameAncestors',
'frame-src' => 'frameSrc',
'img-src' => 'imageSrc',
'media-src' => 'mediaSrc',
'object-src' => 'objectSrc',
'plugin-types' => 'pluginTypes',
'script-src' => 'scriptSrc',
'style-src' => 'styleSrc',
'manifest-src' => 'manifestSrc',
'sandbox' => 'sandbox',
'report-uri' => 'reportURI',
];

/**
* Used for security enforcement
*
Expand Down Expand Up @@ -113,37 +138,37 @@ class ContentSecurityPolicy
/**
* Used for security enforcement
*
* @var string
* @var array|string
*/
protected $reportURI;
protected $scriptSrc = [];

/**
* Used for security enforcement
*
* @var array|string
*/
protected $sandbox = [];
protected $styleSrc = [];

/**
* Used for security enforcement
*
* @var array|string
*/
protected $scriptSrc = [];
protected $manifestSrc = [];

/**
* Used for security enforcement
*
* @var array|string
*/
protected $styleSrc = [];
protected $sandbox = [];

/**
* Used for security enforcement
*
* @var array|string
* @var string|null
*/
protected $manifestSrc = [];
protected $reportURI;

/**
* Used for security enforcement
Expand Down Expand Up @@ -704,26 +729,6 @@ protected function buildHeaders(ResponseInterface $response)
$response->setHeader('Content-Security-Policy', []);
$response->setHeader('Content-Security-Policy-Report-Only', []);

$directives = [
'base-uri' => 'baseURI',
'child-src' => 'childSrc',
'connect-src' => 'connectSrc',
'default-src' => 'defaultSrc',
'font-src' => 'fontSrc',
'form-action' => 'formAction',
'frame-ancestors' => 'frameAncestors',
'frame-src' => 'frameSrc',
'img-src' => 'imageSrc',
'media-src' => 'mediaSrc',
'object-src' => 'objectSrc',
'plugin-types' => 'pluginTypes',
'script-src' => 'scriptSrc',
'style-src' => 'styleSrc',
'manifest-src' => 'manifestSrc',
'sandbox' => 'sandbox',
'report-uri' => 'reportURI',
];

// inject default base & default URIs if needed
if (empty($this->baseURI)) {
$this->baseURI = 'self';
Expand All @@ -733,7 +738,7 @@ protected function buildHeaders(ResponseInterface $response)
$this->defaultSrc = 'self';
}

foreach ($directives as $name => $property) {
foreach ($this->directives as $name => $property) {
if (! empty($this->{$property})) {
$this->addToHeader($name, $this->{$property});
}
Expand Down Expand Up @@ -814,4 +819,20 @@ protected function addToHeader(string $name, $values = null)
$this->reportOnlyHeaders[$name] = implode(' ', $reportSources);
}
}

/**
* Clear the directive.
*
* @param string $directive CSP directive
*/
public function clearDirective(string $directive): void
{
if ($directive === 'report-uris') {
$this->{$this->directives[$directive]} = null;

return;
}

$this->{$this->directives[$directive]} = [];
}
}
18 changes: 18 additions & 0 deletions tests/system/HTTP/ContentSecurityPolicyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -642,4 +642,22 @@ public function testHeaderScriptNonceEmittedOnceGetScriptNonceCalled(): void
$result = $this->getHeaderEmitted('Content-Security-Policy');
$this->assertStringContainsString("script-src 'self' 'nonce-", $result);
}

public function testClearDirective(): void
{
$this->prepare();

$this->csp->addStyleSrc('css.example.com');
$this->csp->clearDirective('style-src');

$this->csp->setReportURI('http://example.com/csp/reports');
$this->csp->clearDirective('report-uri');
$this->csp->finalize($this->response);

$header = $this->response->getHeaderLine('Content-Security-Policy');

$this->assertStringNotContainsString('style-src ', $header);
$this->assertStringNotContainsString('css.example.com', $header);
$this->assertStringNotContainsString('report-uri', $header);
}
}
2 changes: 2 additions & 0 deletions user_guide_src/source/changelogs/v4.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ Others
- ``FileLocatorInterface`` has been added.
- **CodeIgniter:** Added a pseudo-variable ``{memory_usage}`` to show your memory
usage in your view files, which was supported by CodeIgniter 3.
- **CSP:** Added ``ContentSecurityPolicy::clearDirective()`` method to clear
existing CSP directives. See :ref:`csp-clear-directives`.

Message Changes
***************
Expand Down
21 changes: 19 additions & 2 deletions user_guide_src/source/outgoing/csp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ call basis, by providing an optional second parameter to the adding method call.
Runtime Configuration
*********************

If your application needs to make changes at run-time, you can access the instance at ``$this->response->getCSP()`` in your controllers. The
If your application needs to make changes at run-time, you can access the instance at ``$this->response->getCSP()`` in your controllers.

The
class holds a number of methods that map pretty clearly to the appropriate header value that you need to set.
Examples are shown below, with different combinations of parameters, though all accept either a directive
name or an array of them:
Expand All @@ -76,12 +78,27 @@ name or an array of them:
The first parameter to each of the "add" methods is an appropriate string value,
or an array of them.

Report Only
===========

The ``reportOnly()`` method allows you to specify the default reporting treatment
for subsequent sources, unless over-ridden. For instance, you could specify
for subsequent sources, unless over-ridden.

For instance, you could specify
that youtube.com was allowed, and then provide several allowed but reported sources:

.. literalinclude:: csp/013.php

.. _csp-clear-directives:

Clear Directives
================

If you want to clear existing CSP directives, you can use the ``clearDirective()``
method:

.. literalinclude:: csp/014.php

**************
Inline Content
**************
Expand Down
6 changes: 6 additions & 0 deletions user_guide_src/source/outgoing/csp/014.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

// get the CSP instance
$csp = $this->response->getCSP();

$csp->clearDirective('style-src');
Loading