Add support for disallowing domains to the ContentSecurityPolicy

For enhanced security it is important that there is also a way to disallow domains, including the default ones.

With this commit every method gets added a new "disallow" function.
This commit is contained in:
Lukas Reschke 2015-05-20 11:44:37 +02:00
parent 9be6d8cd39
commit a62190a72d
2 changed files with 326 additions and 2 deletions

View file

@ -101,7 +101,7 @@ class ContentSecurityPolicy {
* @since 8.1.0
*/
public function allowEvalScript($state = true) {
$this->evalScriptAllowed= $state;
$this->evalScriptAllowed = $state;
return $this;
}
@ -117,6 +117,18 @@ class ContentSecurityPolicy {
return $this;
}
/**
* Remove the specified allowed script domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowScriptDomain($domain) {
$this->allowedScriptDomains = array_diff($this->allowedScriptDomains, [$domain]);
return $this;
}
/**
* Whether inline CSS snippets are allowed or forbidden
* @param bool $state
@ -140,6 +152,18 @@ class ContentSecurityPolicy {
return $this;
}
/**
* Remove the specified allowed style domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowStyleDomain($domain) {
$this->allowedStyleDomains = array_diff($this->allowedStyleDomains, [$domain]);
return $this;
}
/**
* Allows using fonts from a specific domain. Use * to allow
* fonts from all domains.
@ -152,6 +176,18 @@ class ContentSecurityPolicy {
return $this;
}
/**
* Remove the specified allowed font domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowFontDomain($domain) {
$this->allowedFontDomains = array_diff($this->allowedFontDomains, [$domain]);
return $this;
}
/**
* Allows embedding images from a specific domain. Use * to allow
* images from all domains.
@ -164,6 +200,18 @@ class ContentSecurityPolicy {
return $this;
}
/**
* Remove the specified allowed image domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowImageDomain($domain) {
$this->allowedImageDomains = array_diff($this->allowedImageDomains, [$domain]);
return $this;
}
/**
* To which remote domains the JS connect to.
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
@ -176,7 +224,19 @@ class ContentSecurityPolicy {
}
/**
* From whoch domains media elements can be embedded.
* Remove the specified allowed connect domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowConnectDomain($domain) {
$this->allowedConnectDomains = array_diff($this->allowedConnectDomains, [$domain]);
return $this;
}
/**
* From which domains media elements can be embedded.
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
* @return $this
* @since 8.1.0
@ -186,6 +246,18 @@ class ContentSecurityPolicy {
return $this;
}
/**
* Remove the specified allowed media domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowMediaDomain($domain) {
$this->allowedMediaDomains = array_diff($this->allowedMediaDomains, [$domain]);
return $this;
}
/**
* From which domains objects such as <object>, <embed> or <applet> are executed
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
@ -197,6 +269,18 @@ class ContentSecurityPolicy {
return $this;
}
/**
* Remove the specified allowed object domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowObjectDomain($domain) {
$this->allowedObjectDomains = array_diff($this->allowedObjectDomains, [$domain]);
return $this;
}
/**
* Which domains can be embedded in an iframe
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
@ -208,6 +292,18 @@ class ContentSecurityPolicy {
return $this;
}
/**
* Remove the specified allowed frame domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowFrameDomain($domain) {
$this->allowedFrameDomains = array_diff($this->allowedFrameDomains, [$domain]);
return $this;
}
/**
* Domains from which web-workers and nested browsing content can load elements
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
@ -219,6 +315,18 @@ class ContentSecurityPolicy {
return $this;
}
/**
* Remove the specified allowed child src domain from the allowed domains.
*
* @param string $domain
* @return $this
* @since 8.1.0
*/
public function disallowChildSrcDomain($domain) {
$this->allowedChildSrcDomains = array_diff($this->allowedChildSrcDomains, [$domain]);
return $this;
}
/**
* Get the generated Content-Security-Policy as a string
* @return string

View file

@ -47,6 +47,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowScriptDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowScriptDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' www.owncloud.com 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowScriptDomainMultipleStacked() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org')->disallowScriptDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyScriptAllowInline() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
@ -85,6 +109,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowStyleDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowStyleDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' www.owncloud.com 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowStyleDomainMultipleStacked() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org')->disallowStyleDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyStyleAllowInline() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
@ -121,6 +169,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowImageDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowImageDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowImageDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' www.owncloud.com;font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowImageDomainMultipleStakes() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org')->disallowImageDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyFontDomainValid() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self' www.owncloud.com;connect-src 'self';media-src 'self'";
@ -136,6 +208,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowFontDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowFontDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowFontDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self' www.owncloud.com;connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowFontDomainMultipleStakes() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org')->disallowFontDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyConnectDomainValid() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self' www.owncloud.com;media-src 'self'";
@ -151,6 +247,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowConnectDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowConnectDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self' www.owncloud.com;media-src 'self'";
$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowConnectDomainMultipleStakes() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org')->disallowConnectDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyMediaDomainValid() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self' www.owncloud.com";
@ -166,6 +286,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowMediaDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowMediaDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self' www.owncloud.com";
$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowMediaDomainMultipleStakes() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org')->disallowMediaDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyObjectDomainValid() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';object-src www.owncloud.com";
@ -181,6 +325,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowObjectDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowObjectDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';object-src www.owncloud.com";
$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowObjectDomainMultipleStakes() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org')->disallowObjectDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetAllowedFrameDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';frame-src www.owncloud.com";
@ -196,6 +364,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowFrameDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowFrameDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';frame-src www.owncloud.com";
$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowFrameDomainMultipleStakes() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org')->disallowFrameDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetAllowedChildSrcDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';child-src child.owncloud.com";
@ -211,6 +403,30 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowChildSrcDomain() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowChildSrcDomainMultiple() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self';child-src www.owncloud.com";
$this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testGetPolicyDisallowChildSrcDomainMultipleStakes() {
$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
$this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
$this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
public function testConfigureStacked() {
$expectedPolicy = "default-src 'none';script-src 'self' script.owncloud.org;style-src 'self' style.owncloud.org;img-src 'self' img.owncloud.org;font-src 'self' font.owncloud.org;connect-src 'self' connect.owncloud.org;media-src 'self' media.owncloud.org;object-src objects.owncloud.org;frame-src frame.owncloud.org;child-src child.owncloud.org";