diff --git a/config/config.sample.php b/config/config.sample.php
index 090e8f1f9fa008c89e7dafcd7575216b32583ac6..061f368b20ec69d5a242fb0ecb12f8f7f1abcd79 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -929,15 +929,6 @@ $CONFIG = array(
 	'mssql'
 ),
 
-/**
- * Custom CSP policy, changing this will overwrite the standard policy
- */
-'custom_csp_policy' =>
-	"default-src 'self'; script-src 'self' 'unsafe-eval'; ".
-	"style-src 'self' 'unsafe-inline'; frame-src *; img-src *; ".
-	"font-src 'self' data:; media-src *; connect-src *",
-
-
 /**
  * All other config options
  */
diff --git a/lib/private/response.php b/lib/private/response.php
index cf18115111a016bd41f8bef00c2968295201d3e7..8e4a7d309b01f35beceb65d592cf729f5601f69e 100644
--- a/lib/private/response.php
+++ b/lib/private/response.php
@@ -188,7 +188,7 @@ class OC_Response {
 		}
 	}
 
-	/*
+	/**
 	 * This function adds some security related headers to all requests served via base.php
 	 * The implementation of this function has to happen here to ensure that all third-party
 	 * components (e.g. SabreDAV) also benefit from this headers.
@@ -203,17 +203,20 @@ class OC_Response {
 			header('X-Frame-Options: Sameorigin'); // Disallow iFraming from other domains
 		}
 
-		// Content Security Policy
-		// If you change the standard policy, please also change it in config.sample.php
-		$policy = OC_Config::getValue('custom_csp_policy',
-			'default-src \'self\'; '
+		/**
+		 * FIXME: Content Security Policy for legacy ownCloud components. This
+		 * can be removed once \OCP\AppFramework\Http\Response from the AppFramework
+		 * is used everywhere.
+		 * @see \OCP\AppFramework\Http\Response::getHeaders
+		 */
+		$policy = 'default-src \'self\'; '
 			. 'script-src \'self\' \'unsafe-eval\'; '
 			. 'style-src \'self\' \'unsafe-inline\'; '
 			. 'frame-src *; '
 			. 'img-src *; '
 			. 'font-src \'self\' data:; '
 			. 'media-src *; ' 
-			. 'connect-src *');
+			. 'connect-src *';
 		header('Content-Security-Policy:' . $policy);
 
 		// https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
diff --git a/lib/public/appframework/http/contentsecuritypolicy.php b/lib/public/appframework/http/contentsecuritypolicy.php
new file mode 100644
index 0000000000000000000000000000000000000000..8132237a22860ab99e1d642e4cb2a4c0982c3181
--- /dev/null
+++ b/lib/public/appframework/http/contentsecuritypolicy.php
@@ -0,0 +1,241 @@
+<?php
+/**
+ * Copyright (c) 2015 Lukas Reschke lukas@owncloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\AppFramework\Http;
+
+use OCP\AppFramework\Http;
+
+/**
+ * Class ContentSecurityPolicy is a simple helper which allows applications to
+ * modify the Content-Security-Policy sent by ownCloud. Per default only JavaScript,
+ * stylesheets, images, fonts, media and connections from the same domain
+ * ('self') are allowed.
+ *
+ * Even if a value gets modified above defaults will still get appended. Please
+ * notice that ownCloud ships already with sensible defaults and those policies
+ * should require no modification at all for most use-cases.
+ *
+ * @package OCP\AppFramework\Http
+ */
+class ContentSecurityPolicy {
+	/** @var bool Whether inline JS snippets are allowed */
+	private $inlineScriptAllowed = false;
+	/**
+	 * @var bool Whether eval in JS scripts is allowed
+	 * TODO: Disallow per default
+	 * @link https://github.com/owncloud/core/issues/11925
+	 */
+	private $evalScriptAllowed = true;
+	/** @var array Domains from which scripts can get loaded */
+	private $allowedScriptDomains = [
+		'\'self\'',
+	];
+	/**
+	 * @var bool Whether inline CSS is allowed
+	 * TODO: Disallow per default
+	 * @link https://github.com/owncloud/core/issues/13458
+	 */
+	private $inlineStyleAllowed = true;
+	/** @var array Domains from which CSS can get loaded */
+	private $allowedStyleDomains = [
+		'\'self\'',
+	];
+	/** @var array Domains from which images can get loaded */
+	private $allowedImageDomains = [
+		'\'self\'',
+	];
+	/** @var array Domains to which connections can be done */
+	private $allowedConnectDomains = [
+		'\'self\'',
+	];
+	/** @var array Domains from which media elements can be loaded */
+	private $allowedMediaDomains = [
+		'\'self\'',
+	];
+	/** @var array Domains from which object elements can be loaded */
+	private $allowedObjectDomains = [];
+	/** @var array Domains from which iframes can be loaded */
+	private $allowedFrameDomains = [];
+	/** @var array Domains from which fonts can be loaded */
+	private $allowedFontDomains = [
+		'\'self\'',
+	];
+
+	/**
+	 * Whether inline JavaScript snippets are allowed or forbidden
+	 * @param bool $state
+	 * @return $this
+	 */
+	public function allowInlineScript($state = false) {
+		$this->inlineScriptAllowed = $state;
+		return $this;
+	}
+
+	/**
+	 * Whether eval in JavaScript is allowed or forbidden
+	 * @param bool $state
+	 * @return $this
+	 */
+	public function evalScriptState($state = true) {
+		$this->evalScriptAllowed= $state;
+		return $this;
+	}
+
+	/**
+	 * Allows to execute JavaScript files from a specific domain. Use * to
+	 * allow JavaScript from all domains.
+	 * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+	 * @return $this
+	 */
+	public function addAllowedScriptDomain($domain) {
+		$this->allowedScriptDomains[] = $domain;
+		return $this;
+	}
+
+	/**
+	 * Whether inline CSS snippets are allowed or forbidden
+	 * @param bool $state
+	 * @return $this
+	 */
+	public function allowInlineStyle($state = true) {
+		$this->inlineStyleAllowed = $state;
+		return $this;
+	}
+
+	/**
+	 * Allows to execute CSS files from a specific domain. Use * to allow
+	 * CSS from all domains.
+	 * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+	 * @return $this
+	 */
+	public function addAllowedStyleDomain($domain) {
+		$this->allowedStyleDomains[] = $domain;
+		return $this;
+	}
+
+	/**
+	 * Allows using fonts from a specific domain. Use * to allow
+	 * fonts from all domains.
+	 * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+	 * @return $this
+	 */
+	public function addAllowedFontDomain($domain) {
+		$this->allowedFontDomains[] = $domain;
+		return $this;
+	}
+
+	/**
+	 * Allows embedding images from a specific domain. Use * to allow
+	 * images from all domains.
+	 * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+	 * @return $this
+	 */
+	public function addAllowedImageDomain($domain) {
+		$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.
+	 * @return $this
+	 */
+	public function addAllowedConnectDomain($domain) {
+		$this->allowedConnectDomains[] = $domain;
+		return $this;
+	}
+
+	/**
+	 * From whoch domains media elements can be embedded.
+	 * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+	 * @return $this
+	 */
+	public function addAllowedMediaDomain($domain) {
+		$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.
+	 * @return $this
+	 */
+	public function addAllowedObjectDomain($domain) {
+		$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.
+	 * @return $this
+	 */
+	public function addAllowedFrameDomain($domain) {
+		$this->allowedFrameDomains[] = $domain;
+		return $this;
+	}
+
+	/**
+	 * Get the generated Content-Security-Policy as a string
+	 * @return string
+	 */
+	public function buildPolicy() {
+		$policy = "default-src 'none';";
+
+		if(!empty($this->allowedScriptDomains)) {
+			$policy .= 'script-src ' . implode(' ', $this->allowedScriptDomains);
+			if($this->inlineScriptAllowed) {
+				$policy .= ' \'unsafe-inline\'';
+			}
+			if($this->evalScriptAllowed) {
+				$policy .= ' \'unsafe-eval\'';
+			}
+			$policy .= ';';
+		}
+
+		if(!empty($this->allowedStyleDomains)) {
+			$policy .= 'style-src ' . implode(' ', $this->allowedStyleDomains);
+			if($this->inlineStyleAllowed) {
+				$policy .= ' \'unsafe-inline\'';
+			}
+			$policy .= ';';
+		}
+
+		if(!empty($this->allowedImageDomains)) {
+			$policy .= 'img-src ' . implode(' ', $this->allowedImageDomains);
+			$policy .= ';';
+		}
+
+		if(!empty($this->allowedFontDomains)) {
+			$policy .= 'font-src ' . implode(' ', $this->allowedFontDomains);
+			$policy .= ';';
+		}
+
+		if(!empty($this->allowedConnectDomains)) {
+			$policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains);
+			$policy .= ';';
+		}
+
+		if(!empty($this->allowedMediaDomains)) {
+			$policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains);
+			$policy .= ';';
+		}
+
+		if(!empty($this->allowedObjectDomains)) {
+			$policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains);
+			$policy .= ';';
+		}
+
+		if(!empty($this->allowedFrameDomains)) {
+			$policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains);
+			$policy .= ';';
+		}
+
+		return rtrim($policy, ';');
+	}
+}
diff --git a/lib/public/appframework/http/response.php b/lib/public/appframework/http/response.php
index 67e72cff6d9c13ec19962eaf1abf65e85d3fee56..751c48b4ca98ff66f2314796c2e5834f1e649315 100644
--- a/lib/public/appframework/http/response.php
+++ b/lib/public/appframework/http/response.php
@@ -72,6 +72,9 @@ class Response {
 	 */
 	private $ETag;
 
+	/** @var ContentSecurityPolicy|null Used Content-Security-Policy */
+	private $contentSecurityPolicy = null;
+
 
 	/**
 	 * Caches the response
@@ -186,13 +189,19 @@ class Response {
 	 * @return array the headers
 	 */
 	public function getHeaders() {
-		$mergeWith = array();
+		$mergeWith = [];
 
 		if($this->lastModified) {
 			$mergeWith['Last-Modified'] =
 				$this->lastModified->format(\DateTime::RFC2822);
 		}
 
+		// Build Content-Security-Policy and use default if none has been specified
+		if(is_null($this->contentSecurityPolicy)) {
+			$this->setContentSecurityPolicy(new ContentSecurityPolicy());
+		}
+		$this->headers['Content-Security-Policy'] = $this->contentSecurityPolicy->buildPolicy();
+
 		if($this->ETag) {
 			$mergeWith['ETag'] = '"' . $this->ETag . '"';
 		}
@@ -221,6 +230,25 @@ class Response {
 		return $this;
 	}
 
+	/**
+	 * Set a Content-Security-Policy
+	 * @param ContentSecurityPolicy $csp Policy to set for the response object
+	 * @return $this
+	 */
+	public function setContentSecurityPolicy(ContentSecurityPolicy $csp) {
+		$this->contentSecurityPolicy = $csp;
+		return $this;
+	}
+
+	/**
+	 * Get the currently used Content-Security-Policy
+	 * @return ContentSecurityPolicy|null Used Content-Security-Policy or null if
+	 *                                    none specified.
+	 */
+	public function getContentSecurityPolicy() {
+		return $this->contentSecurityPolicy;
+	}
+
 
 	/**
 	 * Get response status
diff --git a/tests/lib/appframework/controller/ControllerTest.php b/tests/lib/appframework/controller/ControllerTest.php
index 58395d05914c2dea48a34875469fc8d475eb5b2d..3bf63d714a02086282bc78e9f0ce546e0ea983f7 100644
--- a/tests/lib/appframework/controller/ControllerTest.php
+++ b/tests/lib/appframework/controller/ControllerTest.php
@@ -172,11 +172,12 @@ class ControllerTest extends \Test\TestCase {
 
 
 	public function testFormatDataResponseJSON() {
-		$expectedHeaders = array(
+		$expectedHeaders = [
 			'test' => 'something',
 			'Cache-Control' => 'no-cache, must-revalidate',
-			'Content-Type' => 'application/json; charset=utf-8'
-		);
+			'Content-Type' => 'application/json; charset=utf-8',
+			'Content-Security-Policy' => "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'",
+		];
 
 		$response = $this->controller->customDataResponse(array('hi'));
 		$response = $this->controller->buildResponse($response, 'json');
diff --git a/tests/lib/appframework/http/ContentSecurityPolicyTest.php b/tests/lib/appframework/http/ContentSecurityPolicyTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3b30bba33d40289a8bc5faf10eb862d3bf9fa5a0
--- /dev/null
+++ b/tests/lib/appframework/http/ContentSecurityPolicyTest.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Copyright (c) 2015 Lukas Reschke lukas@owncloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+
+namespace OC\AppFramework\Http;
+
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\ContentSecurityPolicy;
+
+/**
+ * Class ContentSecurityPolicyTest
+ *
+ * @package OC\AppFramework\Http
+ */
+class ContentSecurityPolicyTest extends \Test\TestCase {
+
+	/** @var ContentSecurityPolicy */
+	private $contentSecurityPolicy;
+
+	public function setUp() {
+		parent::setUp();
+		$this->contentSecurityPolicy = new ContentSecurityPolicy();
+	}
+
+	public function testGetPolicyDefault() {
+		$defaultPolicy = "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->assertSame($defaultPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyScriptDomainValid() {
+		$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->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyScriptDomainValidMultiple() {
+		$expectedPolicy = "default-src 'none';script-src 'self' www.owncloud.com www.owncloud.org '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->addAllowedScriptDomain('www.owncloud.org');
+		$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'";
+
+		$this->contentSecurityPolicy->allowInlineScript(true);
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyScriptAllowInlineWithDomain() {
+		$expectedPolicy = "default-src 'none';script-src 'self' www.owncloud.com 'unsafe-inline' '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->allowInlineScript(true);
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyScriptDisallowInlineAndEval() {
+		$expectedPolicy = "default-src 'none';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
+
+		$this->contentSecurityPolicy->allowInlineScript(false);
+		$this->contentSecurityPolicy->evalScriptState(false);
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyStyleDomainValid() {
+		$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->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyStyleDomainValidMultiple() {
+		$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' www.owncloud.com www.owncloud.org 'unsafe-inline';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
+
+		$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+		$this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.org');
+		$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'";
+
+		$this->contentSecurityPolicy->allowInlineStyle(true);
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyStyleAllowInlineWithDomain() {
+		$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->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyStyleDisallowInline() {
+		$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self';img-src 'self';font-src 'self';connect-src 'self';media-src 'self'";
+
+		$this->contentSecurityPolicy->allowInlineStyle(false);
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyImageDomainValid() {
+		$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->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyImageDomainValidMultiple() {
+		$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' www.owncloud.com www.owncloud.org;font-src 'self';connect-src 'self';media-src 'self'";
+
+		$this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+		$this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.org');
+		$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'";
+
+		$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyFontDomainValidMultiple() {
+		$expectedPolicy = "default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self' www.owncloud.com www.owncloud.org;connect-src 'self';media-src 'self'";
+
+		$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+		$this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.org');
+		$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'";
+
+		$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyConnectDomainValidMultiple() {
+		$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 www.owncloud.org;media-src 'self'";
+
+		$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+		$this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.org');
+		$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";
+
+		$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyMediaDomainValidMultiple() {
+		$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 www.owncloud.org";
+
+		$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+		$this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.org');
+		$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";
+
+		$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyObjectDomainValidMultiple() {
+		$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 www.owncloud.org";
+
+		$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+		$this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.org');
+		$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";
+
+		$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+
+	public function testGetPolicyFrameDomainValidMultiple() {
+		$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 www.owncloud.org";
+
+		$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+		$this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.org');
+		$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";
+
+		$this->contentSecurityPolicy->allowInlineStyle(false)
+			->evalScriptState(false)
+			->addAllowedScriptDomain('script.owncloud.org')
+			->addAllowedStyleDomain('style.owncloud.org')
+			->addAllowedFontDomain('font.owncloud.org')
+			->addAllowedImageDomain('img.owncloud.org')
+			->addAllowedConnectDomain('connect.owncloud.org')
+			->addAllowedMediaDomain('media.owncloud.org')
+			->addAllowedObjectDomain('objects.owncloud.org')
+			->addAllowedFrameDomain('frame.owncloud.org');
+		$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+	}
+}
diff --git a/tests/lib/appframework/http/DataResponseTest.php b/tests/lib/appframework/http/DataResponseTest.php
index e91d3cefea9f721a5ccada4c13d1ebb187e1c7ae..ca0582e10e5b643822d06a95a9f2fab0cf602849 100644
--- a/tests/lib/appframework/http/DataResponseTest.php
+++ b/tests/lib/appframework/http/DataResponseTest.php
@@ -66,7 +66,10 @@ class DataResponseTest extends \Test\TestCase {
 		$headers = array('test' => 'something');
 		$response = new DataResponse($data, $code, $headers);
 
-		$expectedHeaders = array('Cache-Control' => 'no-cache, must-revalidate');
+		$expectedHeaders = [
+			'Cache-Control' => 'no-cache, must-revalidate',
+			'Content-Security-Policy' => "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'",
+		];
 		$expectedHeaders = array_merge($expectedHeaders, $headers);
 
 		$this->assertEquals($data, $response->getData());
diff --git a/tests/lib/appframework/http/ResponseTest.php b/tests/lib/appframework/http/ResponseTest.php
index b4352348bae1322029c4147df45adc5baad9e95f..77e9441b52cad59e8483f3fc1adb5d2ad0bb026a 100644
--- a/tests/lib/appframework/http/ResponseTest.php
+++ b/tests/lib/appframework/http/ResponseTest.php
@@ -49,7 +49,7 @@ class ResponseTest extends \Test\TestCase {
 	}
 
 
-	function testSetHeaders(){
+	public function testSetHeaders() {
 		$expected = array(
 			'Last-Modified' => 1,
 			'ETag' => 3,
@@ -58,15 +58,40 @@ class ResponseTest extends \Test\TestCase {
 
 		$this->childResponse->setHeaders($expected);
 		$headers = $this->childResponse->getHeaders();
+		$expected['Content-Security-Policy'] = "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->assertEquals($expected, $headers);
 	}
 
+	public function testOverwriteCsp() {
+		$expected = [
+			'Content-Security-Policy' => "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'",
+		];
+		$policy = new Http\ContentSecurityPolicy();
+		$policy->allowInlineScript(true);
+
+		$this->childResponse->setContentSecurityPolicy($policy);
+		$headers = $this->childResponse->getHeaders();
+
+		$this->assertEquals(array_merge($expected, $headers), $headers);
+	}
+
+	public function testGetCsp() {
+		$policy = new Http\ContentSecurityPolicy();
+		$policy->allowInlineScript(true);
+
+		$this->childResponse->setContentSecurityPolicy($policy);
+		$this->assertEquals($policy, $this->childResponse->getContentSecurityPolicy());
+	}
+
+	public function testGetCspEmpty() {
+		$this->assertNull($this->childResponse->getContentSecurityPolicy());
+	}
 
 	public function testAddHeaderValueNullDeletesIt(){
 		$this->childResponse->addHeader('hello', 'world');
 		$this->childResponse->addHeader('hello', null);
-		$this->assertEquals(1, count($this->childResponse->getHeaders()));
+		$this->assertEquals(2, count($this->childResponse->getHeaders()));
 	}