diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php index f97a4fe54..355e19caa 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -194,7 +194,15 @@ class Application extends \RainLoop\Config\AbstractConfig 'content_security_policy' => array('', 'For example to allow all images use "img-src https:". More info at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#directives'), 'csp_report' => array(false, 'Report CSP errors to PHP and/or SnappyMail Log'), 'encrypt_cipher' => array('aes-256-cbc-hmac-sha1', 'A valid cipher method from https://php.net/openssl_get_cipher_methods'), - 'cookie_samesite' => array('Strict', 'Strict, Lax or None') + 'cookie_samesite' => array('Strict', 'Strict, Lax or None'), + 'secfetch_allow' => array('', 'Additional allowed Sec-Fetch combinations separated by ";". +For example: +* Allow iframe on same domain in any mode: dest=iframe,site=same-origin +* Allow navigate to iframe on same domain: mode=navigate,dest=iframe,site=same-origin +* Allow navigate to iframe on (sub)domain: mode=navigate,dest=iframe,site=same-site +* Allow navigate to iframe from any domain: mode=navigate,dest=iframe,site=cross-site + +Default is "site=same-origin;site=none"') ), 'admin_panel' => array( diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Service.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Service.php index ceca2018b..6875624fe 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Service.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Service.php @@ -101,7 +101,7 @@ abstract class Service $sResult = ''; if (\count($aPaths) && !empty($aPaths[0]) && 'index' !== \strtolower($aPaths[0])) { - if ('mailto' !== \strtolower($aPaths[0]) && !\SnappyMail\HTTP\SecFetch::isSameOrigin()) { + if ('mailto' !== \strtolower($aPaths[0]) && !\SnappyMail\HTTP\SecFetch::matchAnyRule($oConfig->Get('security', 'secfetch_allow', ''))) { \MailSo\Base\Http::StatusHeader(403); echo $oServiceActions->ErrorTemplates('Access Denied.', "Disallowed Sec-Fetch diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/http/secfetch.php b/snappymail/v/0.0.0/app/libraries/snappymail/http/secfetch.php index 406ffc2a9..6d262fbfa 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/http/secfetch.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/http/secfetch.php @@ -107,11 +107,42 @@ abstract class SecFetch public static function isSameOrigin() : bool { - return !isset($_SERVER['HTTP_SEC_FETCH_SITE']) || 'same-origin' === $_SERVER['HTTP_SEC_FETCH_SITE'] // Fulguris incognito: Dest = document, Mode = navigate, Site = none, User = true || 'none' === $_SERVER['HTTP_SEC_FETCH_SITE']; } + /** + * $rules = Additional allowed Sec-Fetch combinations separated by ";". + * For example: + * Allow iframe on same domain in any mode: dest=iframe,site=same-origin + * Allow navigate to iframe on same domain: mode=navigate,dest=iframe,site=same-origin + * Allow navigate to iframe on (sub)domain: mode=navigate,dest=iframe,site=same-site + * Allow navigate to iframe from any domain: mode=navigate,dest=iframe,site=cross-site + * + * Default is "site=same-origin;site=none" + */ + public static function matchAnyRule(string $rules) : bool + { + if (!isset($_SERVER['HTTP_SEC_FETCH_SITE'])) { + return true; + } + $secfetch = \explode(';', 'site=same-origin;site=none;' . $rules); + foreach ($secfetch as $rule) { + if (\preg_match_all('/(dest|mode|site)=([^,]+)/', $rule, $matches, PREG_SET_ORDER)) { + $data = ['dest'=>'','mode'=>'','site'=>'']; + foreach ($matches as $match) { + $data[$match[1]] = $match[2]; + } + if ((!$data['site'] || static::site($data['site'])) + && (!$data['dest'] || !isset($_SERVER['HTTP_SEC_FETCH_DEST']) || static::dest($data['dest'])) + && (!$data['mode'] || !isset($_SERVER['HTTP_SEC_FETCH_MODE']) || static::mode($data['mode'])) + ) { + return true; + } + } + } + } + }