Pārlūkot izejas kodu

Add option for CSP frame-ancestors (#7857)

* Add option for CSP frame-ancestors
https://github.com/FreshRSS/FreshRSS/discussions/7856

* Revert contentSelectorPreviewAction

* Same for f.php and api

* Fix double init in f.php

* No sandbox for API page
Alexandre Alapetite 6 mēneši atpakaļ
vecāks
revīzija
bc3e4c8fa4

+ 2 - 2
app/Controllers/indexController.php

@@ -58,7 +58,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
 			'default-src' => "'self'",
 			'frame-src' => '*',
 			'img-src' => '* data: blob:',
-			'frame-ancestors' => "'none'",
+			'frame-ancestors' => FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'",
 			'media-src' => '*',
 		]);
 
@@ -147,7 +147,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
 			'default-src' => "'self'",
 			'frame-src' => '*',
 			'img-src' => '* data: blob:',
-			'frame-ancestors' => "'none'",
+			'frame-ancestors' => FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'",
 			'media-src' => '*',
 		]);
 	}

+ 1 - 1
app/Controllers/statsController.php

@@ -29,7 +29,7 @@ class FreshRSS_stats_Controller extends FreshRSS_ActionController {
 
 		$this->_csp([
 			'default-src' => "'self'",
-			'frame-ancestors' => "'none'",
+			'frame-ancestors' => FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'",
 			'img-src' => '* data: blob:',
 		]);
 

+ 2 - 2
app/Controllers/subscriptionController.php

@@ -48,7 +48,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
 
 		$this->_csp([
 			'default-src' => "'self'",
-			'frame-ancestors' => "'none'",
+			'frame-ancestors' => FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'",
 			'img-src' => "'self' blob:",
 		]);
 
@@ -118,7 +118,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
 
 		$this->_csp([
 			'default-src' => "'self'",
-			'frame-ancestors' => "'none'",
+			'frame-ancestors' => FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'",
 			'img-src' => "'self' blob:",
 		]);
 

+ 1 - 1
app/FreshRSS.php

@@ -34,7 +34,7 @@ class FreshRSS extends Minz_FrontController {
 			// Relax Content Security Policy to allow external images if a custom logo HTML is used
 			Minz_ActionController::_defaultCsp([
 				'default-src' => "'self'",
-				'frame-ancestors' => "'none'",
+				'frame-ancestors' => FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'",
 				'img-src' => '* data:',
 			]);
 		}

+ 3 - 0
config.default.php

@@ -88,6 +88,9 @@ return [
 	#	For more information see: https://freshrss.github.io/FreshRSS/en/admins/10_ServerConfig.html#security
 	'suppress_csp_warning' => false,
 
+	# Content-Security-Policy frame-ancestors
+	'csp.frame-ancestors' => "'none'",
+
 	# Enable or not the use of syslog to log the activity of
 	#	SimplePie, which is retrieving RSS feeds via HTTP requests.
 	'simplepie_syslog_enabled' => true,

+ 2 - 1
lib/lib_rss.php

@@ -1100,7 +1100,8 @@ function errorMessageInfo(string $errorTitle, string $error = ''): string {
 		$details = "<pre>{$details}</pre>";
 	}
 
-	header("Content-Security-Policy: default-src 'self'; frame-ancestors 'none'");
+	header("Content-Security-Policy: default-src 'self'; frame-ancestors " .
+		(FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'"));
 	header('Referrer-Policy: same-origin');
 
 	return <<<MSG

+ 13 - 7
p/api/index.php

@@ -1,12 +1,18 @@
 <?php
-	declare(strict_types=1);
-	require dirname(__DIR__, 2) . '/constants.php';
-	require LIB_PATH . '/lib_rss.php';	//Includes class autoloader
-	header("Content-Security-Policy: default-src 'self'; frame-ancestors 'none'");
-	header('X-Content-Type-Options: nosniff');
+declare(strict_types=1);
+require dirname(__DIR__, 2) . '/constants.php';
+require LIB_PATH . '/lib_rss.php';	//Includes class autoloader
 
-	FreshRSS_Context::initSystem();
-	Minz_Translate::init(Minz_Translate::getLanguage(null, Minz_Request::getPreferredLanguages(), null));
+FreshRSS_Context::initSystem();
+if (!FreshRSS_Context::hasSystemConf()) {
+	header('HTTP/1.1 500 Internal Server Error');
+	die('Invalid system init!');
+}
+$frameAncestors = FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'";
+header("Content-Security-Policy: default-src 'self'; frame-ancestors $frameAncestors");
+header('X-Content-Type-Options: nosniff');
+
+Minz_Translate::init(Minz_Translate::getLanguage(null, Minz_Request::getPreferredLanguages(), null));
 ?>
 <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-GB" lang="en-GB">

+ 8 - 4
p/api/query.php

@@ -176,12 +176,14 @@ if (($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') {
 
 if (in_array($format, ['rss', 'atom'], true)) {
 	header('Content-Type: application/rss+xml; charset=utf-8');
-	header("Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; sandbox");
+	header("Content-Security-Policy: default-src 'none'; sandbox; frame-ancestors " .
+		(FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'"));
 	$view->_layout(null);
 	$view->_path('index/rss.phtml');
 } elseif (in_array($format, ['greader', 'json'], true)) {
 	header('Content-Type: application/json; charset=utf-8');
-	header("Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; sandbox");
+	header("Content-Security-Policy: default-src 'none'; sandbox; frame-ancestors " .
+		(FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'"));
 	$view->_layout(null);
 	$view->type = 'query/' . $token;
 	$view->list_title = $query->getName();
@@ -193,11 +195,13 @@ if (in_array($format, ['rss', 'atom'], true)) {
 		die();
 	}
 	header('Content-Type: application/xml; charset=utf-8');
-	header("Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; sandbox");
+	header("Content-Security-Policy: default-src 'none'; sandbox; frame-ancestors " .
+		(FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'"));
 	$view->_layout(null);
 	$view->_path('index/opml.phtml');
 } else {
-	header("Content-Security-Policy: default-src 'self'; frame-src *; img-src * data:; frame-ancestors 'none'; media-src *");
+	header("Content-Security-Policy: default-src 'self'; frame-src *; img-src * data:; media-src *; frame-ancestors " .
+		(FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'"));
 	$view->_layout('layout');
 	$view->_path('index/html.phtml');
 }

+ 2 - 1
p/ext.php

@@ -94,7 +94,8 @@ if (!is_valid_path($absolute_filename)) {
 $content_type = FreshRSS_extension_Controller::MIME_TYPES[$file_type];
 header("Content-Type: {$content_type}");
 header("Content-Disposition: inline; filename='{$file_name}'");
-header("Content-Security-Policy: default-src 'self'; frame-ancestors 'none'");
+header("Content-Security-Policy: default-src 'self'; frame-ancestors " .
+	(FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'"));
 header('X-Content-Type-Options: nosniff');
 header('Referrer-Policy: same-origin');
 

+ 7 - 6
p/f.php

@@ -5,7 +5,13 @@ require LIB_PATH . '/lib_rss.php';	//Includes class autoloader
 require LIB_PATH . '/favicons.php';
 require LIB_PATH . '/http-conditional.php';
 
-header("Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; sandbox");
+FreshRSS_Context::initSystem();
+if (!FreshRSS_Context::hasSystemConf()) {
+	header('HTTP/1.1 500 Internal Server Error');
+	die('Invalid system init!');
+}
+$frameAncestors = FreshRSS_Context::systemConf()->attributeString('csp.frame-ancestors') ?? "'none'";
+header("Content-Security-Policy: default-src 'none'; frame-ancestors $frameAncestors; sandbox");
 header('X-Content-Type-Options: nosniff');
 
 $no_cache = file_exists(DATA_PATH . '/no-cache.txt');
@@ -46,11 +52,6 @@ if (($ico_mtime == false || $ico_mtime < $txt_mtime || ($ico_mtime < time() - (m
 		exit();
 	}
 
-	FreshRSS_Context::initSystem();
-	if (!FreshRSS_Context::hasSystemConf()) {
-		header('HTTP/1.1 500 Internal Server Error');
-		die('Invalid system init!');
-	}
 	if (!download_favicon($url, $ico)) {
 		// Download failed
 		if ($ico_mtime == false) {