diff --git a/application/ajaxwebpage.class.inc.php b/application/ajaxwebpage.class.inc.php index 12f47ffa3..bbe93367d 100644 --- a/application/ajaxwebpage.class.inc.php +++ b/application/ajaxwebpage.class.inc.php @@ -44,7 +44,7 @@ class ajax_page extends WebPage implements iTabbedPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); $this->m_oTabs = new TabManager(); $this->sContentType = 'text/html'; $this->sContentDisposition = 'inline'; diff --git a/application/csvpage.class.inc.php b/application/csvpage.class.inc.php index f6a4639bd..9a34dbb53 100644 --- a/application/csvpage.class.inc.php +++ b/application/csvpage.class.inc.php @@ -35,7 +35,7 @@ class CSVPage extends WebPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); //$this->add_header("Content-Transfer-Encoding: binary"); } diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php index 2e9a86275..328a472de 100644 --- a/application/itopwebpage.class.inc.php +++ b/application/itopwebpage.class.inc.php @@ -74,7 +74,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); $this->add_linked_stylesheet("../css/jquery.treeview.css"); $this->add_linked_stylesheet("../css/jquery.autocomplete.css"); $this->add_linked_stylesheet("../css/jquery-ui-timepicker-addon.css"); diff --git a/application/loginwebpage.class.inc.php b/application/loginwebpage.class.inc.php index 07a2fd69d..d3f0c6cde 100644 --- a/application/loginwebpage.class.inc.php +++ b/application/loginwebpage.class.inc.php @@ -87,7 +87,7 @@ class LoginWebPage extends NiceWebPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); } public function SetStyleSheet() diff --git a/application/webpage.class.inc.php b/application/webpage.class.inc.php index 344d91542..111bc43f5 100644 --- a/application/webpage.class.inc.php +++ b/application/webpage.class.inc.php @@ -482,6 +482,23 @@ class WebPage implements Page $this->a_headers[] = $s_header; } + /** + * @param string|null $sHeaderValue for example `SAMESITE`. If null will set the header using the config parameter value. + * + * @since 2.7.2-2 3.0.0 N°3416 + * @uses security_header_xframe config parameter + * @uses \utils::GetConfig() + * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options + */ + public function add_xframe_options($sHeaderValue = null) + { + if (is_null($sHeaderValue)) { + $sHeaderValue = utils::GetConfig()->Get('security_header_xframe'); + } + + $this->add_header('X-Frame-Options: '.$sHeaderValue); + } + /** * Add needed headers to the page so that it will no be cached */ @@ -490,7 +507,7 @@ class WebPage implements Page $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); //FIXME shouldn't be done here !!!!! } /** diff --git a/application/xmlpage.class.inc.php b/application/xmlpage.class.inc.php index 3310f3772..0ac2dcc6d 100644 --- a/application/xmlpage.class.inc.php +++ b/application/xmlpage.class.inc.php @@ -46,7 +46,7 @@ class XMLPage extends WebPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); $this->add_header("Content-location: export.xml"); } diff --git a/core/config.class.inc.php b/core/config.class.inc.php index de0df09a8..0947b20b1 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1249,6 +1249,14 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => false, ), + 'security_header_xframe' => [ + 'type' => 'string', + 'description' => 'Value of the X-Frame-Options HTTP header sent by iTop. Possible values : DENY, SAMEORIGIN, or empty string.', + 'default' => 'SAMEORIGIN', + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], ); diff --git a/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php b/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php index 9bbb2da35..1a01bc88f 100644 --- a/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php +++ b/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php @@ -4,20 +4,20 @@ class HubConnectorPage extends NiceWebPage { public function __construct($sTitle) { - parent::__construct($sTitle); + parent::__construct($sTitle); $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); - $sImagesDir = utils::GetAbsoluteUrlAppRoot().'images'; - $sModuleImagesDir = utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/images'; - - $sUserPrefs = appUserPreferences::GetAsJSON(); - $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js'); - $this->add_script( -<<add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js'); + $this->add_script( + << 0) { - $oPage->add_header("Expires: "); // Reset the value set in ajax_page $oPage->add_header("Cache-Control: no-transform,public,max-age=$iCacheSec,s-maxage=$iCacheSec"); $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? + $oPage->add_header("Expires: "); // Reset the value set in ajax_page + $oPage->add_xframe_options(''); $oPage->add_header("Last-Modified: Wed, 15 Jun 2015 13:21:15 GMT"); // An arbitrary date in the past is ok } } @@ -76,12 +77,12 @@ try $id = utils::ReadParam('id', ''); $sSecret = utils::ReadParam('s', ''); $iCacheSec = 31556926; // One year ahead: an inline image cannot change - if (!empty($id) && !empty($sSecret)) - { + if (!empty($id) && !empty($sSecret)) { ormDocument::DownloadDocument($oPage, 'InlineImage', $id, 'contents', 'inline', 'secret', $sSecret); - $oPage->add_header("Expires: "); // Reset the value set in ajax_page $oPage->add_header("Cache-Control: no-transform,public,max-age=$iCacheSec,s-maxage=$iCacheSec"); $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? + $oPage->add_header("Expires: "); // Reset the value set in ajax_page + $oPage->add_xframe_options(''); $oPage->add_header("Last-Modified: Wed, 15 Jun 2016 13:21:15 GMT"); // An arbitrary date in the past is ok } break; @@ -92,6 +93,7 @@ try $oPage->SetContentType('text/javascript'); $oPage->add_header('Cache-control: public, max-age=86400'); // Cache for 24 hours $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? + $oPage->add_xframe_options(''); $oPage->add(file_get_contents(Utils::GetCachePath().$sSignature.'.js')); break; diff --git a/pages/ajax.render.php b/pages/ajax.render.php index 8fe1dcd00..e15a8f621 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -961,7 +961,7 @@ try if (!empty($sClass) && ($sClass != 'InlineImage') && !empty($id) && !empty($sField)) { $oKPI = new ExecutionKPI(); - $oPage->add_header('X-Frame-Options:'); // resets header, see N°3416 + $oPage->add_xframe_options(''); // resets header, see N°3416 ormDocument::DownloadDocument($oPage, $sClass, $id, $sField, 'inline'); $oKPI->ComputeAndReport('Data fetch and format'); } diff --git a/sources/application/TwigBase/Controller/Controller.php b/sources/application/TwigBase/Controller/Controller.php index 0a1309916..68b0e8887 100644 --- a/sources/application/TwigBase/Controller/Controller.php +++ b/sources/application/TwigBase/Controller/Controller.php @@ -558,7 +558,7 @@ abstract class Controller { case 'html': $this->m_oPage = new iTopWebPage($this->GetOperationTitle()); - $this->m_oPage->add_header('X-Frame-Options: deny'); + $this->m_oPage->add_xframe_options(); break; case 'ajax': diff --git a/webservices/export-v2.php b/webservices/export-v2.php index 0efd4243f..64c850bfb 100644 --- a/webservices/export-v2.php +++ b/webservices/export-v2.php @@ -44,7 +44,7 @@ function ReportErrorAndExit($sErrorMessage) else { $oP = new WebPage("iTop - Export"); - $oP->add_header('X-Frame-Options: deny'); + $oP->add_xframe_options(); $oP->p('ERROR: '.$sErrorMessage); $oP->output(); exit(-1); @@ -61,10 +61,9 @@ function ReportErrorAndUsage($sErrorMessage) $oP->output(); exit(-1); } - else - { + else { $oP = new WebPage("iTop - Export"); - $oP->add_header('X-Frame-Options: deny'); + $oP->add_xframe_options(); $oP->p('ERROR: '.$sErrorMessage); Usage($oP); $oP->output(); @@ -728,19 +727,17 @@ try if ($sMimeType == 'text/html') { // Note: Using NiceWebPage only for HTML export as it includes JS scripts & files, which makes no sense in other export formats. More over, it breaks Excel spreadsheet import. - if($oExporter instanceof HTMLBulkExport) - { + if($oExporter instanceof HTMLBulkExport) { $oP = new NiceWebPage('iTop export'); - $oP->add_header('X-Frame-Options: deny'); + $oP->add_xframe_options(); $oP->add_ready_script("$('table.listResults').tablesorter({widgets: ['MyZebra']});"); $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css'); $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css'); } - else - { + else { $oP = new WebPage('iTop export'); - $oP->add_header('X-Frame-Options: deny'); - $oP->add_style("table br { mso-data-placement:same-cell; }"); // Trick for Excel: keep line breaks inside the same cell ! + $oP->add_xframe_options(); + $oP->add_style("table br { mso-data-placement:same-cell; }"); // Trick for Excel: keep line breaks inside the same cell ! } $oP->add_style("body { overflow: auto; }"); } @@ -760,10 +757,9 @@ catch (BulkExportMissingParameterException $e) Usage($oP); $oP->output(); } -catch (Exception $e) -{ +catch (Exception $e) { $oP = new WebPage('iTop Export'); - $oP->add_header('X-Frame-Options: deny'); + $oP->add_xframe_options(); $oP->add('Error: '.$e->getMessage()); IssueLog::Error($e->getMessage()."\n".$e->getTraceAsString()); $oP->output();