aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2025-09-21 13:29:58 +0200
committerGravatar GitHub <noreply@github.com> 2025-09-21 13:29:58 +0200
commitbc3e4c8fa4bae9591166e12caa3fb6bf73893102 (patch)
treeee38afd776e08461ba22bdbc10fe4c17d5bff172
parentf1cf57b5b713527b4521c4552b5f1ac023ee3adc (diff)
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
-rw-r--r--app/Controllers/indexController.php4
-rw-r--r--app/Controllers/statsController.php2
-rw-r--r--app/Controllers/subscriptionController.php4
-rw-r--r--app/FreshRSS.php2
-rw-r--r--config.default.php3
-rw-r--r--lib/lib_rss.php3
-rw-r--r--p/api/index.php20
-rw-r--r--p/api/query.php12
-rw-r--r--p/ext.php3
-rw-r--r--p/f.php13
10 files changed, 41 insertions, 25 deletions
diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php
index 736cc8258..7c66d308a 100644
--- a/app/Controllers/indexController.php
+++ b/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' => '*',
]);
}
diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php
index ddb6fcb34..4491443c0 100644
--- a/app/Controllers/statsController.php
+++ b/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:',
]);
diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php
index 424b9a776..6573c0eb3 100644
--- a/app/Controllers/subscriptionController.php
+++ b/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:",
]);
diff --git a/app/FreshRSS.php b/app/FreshRSS.php
index 62e91ff95..cac803329 100644
--- a/app/FreshRSS.php
+++ b/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:',
]);
}
diff --git a/config.default.php b/config.default.php
index 91eca5597..89b2cfd25 100644
--- a/config.default.php
+++ b/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,
diff --git a/lib/lib_rss.php b/lib/lib_rss.php
index 532a9902a..0e916616d 100644
--- a/lib/lib_rss.php
+++ b/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
diff --git a/p/api/index.php b/p/api/index.php
index 279826aa5..03db02188 100644
--- a/p/api/index.php
+++ b/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">
diff --git a/p/api/query.php b/p/api/query.php
index 8aedd8ecf..4618f3e1b 100644
--- a/p/api/query.php
+++ b/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');
}
diff --git a/p/ext.php b/p/ext.php
index 71922ac01..4ee9eb1ae 100644
--- a/p/ext.php
+++ b/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');
diff --git a/p/f.php b/p/f.php
index 5b7b7474b..604081dd0 100644
--- a/p/f.php
+++ b/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) {