Skip to content

Commit

Permalink
Allow to use custom request matcher
Browse files Browse the repository at this point in the history
This adds an option to allow the use of a custom
request matcher, e.g. to exclude certain paths.
  • Loading branch information
ihmels committed Jun 24, 2021
1 parent 40d5ac1 commit 77d8f6d
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### 2.11.x (2021-xx-xx)
* Added `csp > request_matcher` option to allow the use of a custom request matcher (`Symfony\Component\HttpFoundation\RequestMatcherInterface`)

### 2.10.1 (2020-06-18)
* Fix ContentSecurityPolicyController

Expand Down
1 change: 1 addition & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ private function addCspNode()
->canBeDisabled()
// CSP is enabled by default to ensure BC
->children()
->scalarNode('request_matcher')->defaultNull()->end()
->arrayNode('hosts')->prototype('scalar')->end()->defaultValue(array())->end()
->arrayNode('content_types')->prototype('scalar')->end()->defaultValue(array())->end()
->arrayNode('report_endpoint')
Expand Down
4 changes: 4 additions & 0 deletions DependencyInjection/NelmioSecurityExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ public function load(array $configs, ContainerBuilder $container)
$cspListenerDefinition->setArguments(array($reportDefinition, $enforceDefinition, new Reference('nelmio_security.nonce_generator'), new Reference('nelmio_security.sha_computer'), (bool) $cspConfig['compat_headers'], $cspConfig['hosts'], $cspConfig['content_types']));
$container->setParameter('nelmio_security.csp.hash_algorithm', $cspConfig['hash']['algorithm']);

if (isset($cspConfig['request_matcher'])) {
$cspListenerDefinition->setArgument(7, new Reference($cspConfig['request_matcher']));
}

$cspViolationLogFilterDefinition = $container->getDefinition('nelmio_security.csp_report.filter');

$container->setParameter('nelmio_security.csp.report_log_level', $cspConfig['report_endpoint']['log_level']);
Expand Down
13 changes: 11 additions & 2 deletions EventListener/ContentSecurityPolicyListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Nelmio\SecurityBundle\ContentSecurityPolicy\NonceGenerator;
use Nelmio\SecurityBundle\ContentSecurityPolicy\ShaComputer;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
Expand All @@ -37,8 +38,9 @@ class ContentSecurityPolicyListener extends AbstractContentTypeRestrictableListe
protected $sha;
protected $nonceGenerator;
protected $shaComputer;
protected $requestMatcher;

public function __construct(DirectiveSet $report, DirectiveSet $enforce, NonceGenerator $nonceGenerator, ShaComputer $shaComputer, $compatHeaders = true, array $hosts = array(), array $contentTypes = array())
public function __construct(DirectiveSet $report, DirectiveSet $enforce, NonceGenerator $nonceGenerator, ShaComputer $shaComputer, $compatHeaders = true, array $hosts = array(), array $contentTypes = array(), RequestMatcherInterface $requestMatcher = null)
{
parent::__construct($contentTypes);
$this->report = $report;
Expand All @@ -47,6 +49,7 @@ public function __construct(DirectiveSet $report, DirectiveSet $enforce, NonceGe
$this->hosts = $hosts;
$this->nonceGenerator = $nonceGenerator;
$this->shaComputer = $shaComputer;
$this->requestMatcher = $requestMatcher;
}

/**
Expand Down Expand Up @@ -163,7 +166,13 @@ public function onKernelResponse($e)
return;
}

if ((empty($this->hosts) || in_array($e->getRequest()->getHost(), $this->hosts, true)) && $this->isContentTypeValid($response)) {
if ($this->requestMatcher) {
$match = $this->requestMatcher->matches($request);
} else {
$match = empty($this->hosts) || in_array($e->getRequest()->getHost(), $this->hosts, true);
}

if ($match && $this->isContentTypeValid($response)) {
$signatures = $this->sha;
if ($this->scriptNonce) {
$signatures['script-src'][] = 'nonce-'.$this->scriptNonce;
Expand Down

0 comments on commit 77d8f6d

Please sign in to comment.