diff --git a/doc/config.rst b/doc/config.rst index 6099d80c3d..6a5d7cf813 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -119,6 +119,15 @@ Basic settings Show warning about incomplete translations on certain threshold. +.. config:option:: $cfg['AllowThirdPartyFraming'] + + :type: boolean + :default: false + + Setting this to ``true`` allows phpMyAdmin to be included inside a frame, + and is a potential security hole allowing cross-frame scripting attacks or + clickjacking. + Server connection settings -------------------------- diff --git a/js/cross_framing_protection.js b/js/cross_framing_protection.js new file mode 100644 index 0000000000..6fb780350f --- /dev/null +++ b/js/cross_framing_protection.js @@ -0,0 +1,14 @@ +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Conditionally included if third-party framing is not allowed + * + */ + +try { + if (top != self) { + top.location.href = self.location.href; + } +} catch(e) { + alert("Redirecting... (error: " + e); + top.location.href = self.location.href; +} diff --git a/libraries/Header.class.php b/libraries/Header.class.php index 1392bc3e3d..810d556904 100644 --- a/libraries/Header.class.php +++ b/libraries/Header.class.php @@ -158,6 +158,12 @@ class PMA_Header $this->_scripts->addFile('jquery/jquery.ba-hashchange-1.3.js'); $this->_scripts->addFile('jquery/jquery.debounce-1.0.5.js'); $this->_scripts->addFile('jquery/jquery.menuResizer-1.0.js'); + + // Cross-framing protection + if ($GLOBALS['cfg']['AllowThirdPartyFraming'] === false) { + $this->_scripts->addFile('cross_framing_protection.js'); + } + $this->_scripts->addFile('rte.js'); // Here would not be a good place to add CodeMirror because @@ -449,6 +455,12 @@ class PMA_Header */ $GLOBALS['now'] = gmdate('D, d M Y H:i:s') . ' GMT'; if (! defined('TESTSUITE')) { + /* Prevent against ClickJacking by disabling framing */ + if (! $GLOBALS['cfg']['AllowThirdPartyFraming']) { + header( + 'X-Frame-Options: DENY' + ); + } header( "X-Content-Security-Policy: default-src 'self' " . $GLOBALS['cfg']['CSPAllow'] . ';' diff --git a/libraries/Scripts.class.php b/libraries/Scripts.class.php index c0d64d8ab1..a3057d7e0b 100644 --- a/libraries/Scripts.class.php +++ b/libraries/Scripts.class.php @@ -129,6 +129,7 @@ class PMA_Scripts || strpos($filename, 'ajax.js') !== false || strpos($filename, 'navigation.js') !== false || strpos($filename, 'get_image.js.php') !== false + || strpos($filename, 'cross_framing_protection.js') !== false ) { return 0; } else { diff --git a/libraries/config.default.php b/libraries/config.default.php index 598573c508..d164d768e9 100644 --- a/libraries/config.default.php +++ b/libraries/config.default.php @@ -83,6 +83,14 @@ $cfg['ReservedWordDisableWarning'] = false; */ $cfg['TranslationWarningThreshold'] = 80; +/** + * Allows phpMyAdmin to be included from a other document in a frame; + * setting this to true is a potential security hole + * + * @global boolean $cfg['AllowThirdPartyFraming'] + */ +$cfg['AllowThirdPartyFraming'] = false; + /** * The 'cookie' auth_type uses blowfish algorithm to encrypt the password. If * at least one server configuration uses 'cookie' auth_type, enter here a diff --git a/libraries/config/messages.inc.php b/libraries/config/messages.inc.php index 42d72835cc..350bb0df0f 100644 --- a/libraries/config/messages.inc.php +++ b/libraries/config/messages.inc.php @@ -16,6 +16,8 @@ if (!function_exists('__')) { $strConfigAllowArbitraryServer_desc = __('If enabled user can enter any MySQL server in login form for cookie auth'); $strConfigAllowArbitraryServer_name = __('Allow login to any MySQL server'); +$strConfigAllowThirdPartyFraming_desc = __('Enabling this allows a page located on a different domain to call phpMyAdmin inside a frame, and is a potential [strong]security hole[/strong] allowing cross-frame scripting attacks'); +$strConfigAllowThirdPartyFraming_name = __('Allow third party framing'); $strConfigAllowUserDropDatabase_name = __('Show "Drop database" link to normal users'); $strConfigblowfish_secret_desc = __('Secret passphrase used for encrypting cookies in [kbd]cookie[/kbd] authentication'); $strConfigblowfish_secret_name = __('Blowfish secret'); diff --git a/libraries/config/setup.forms.php b/libraries/config/setup.forms.php index bb712cabca..f172462d7d 100644 --- a/libraries/config/setup.forms.php +++ b/libraries/config/setup.forms.php @@ -136,7 +136,8 @@ $forms['Features']['Other_core_settings'] = array( 'MemoryLimit', 'SkipLockedTables', 'DisableMultiTableMaintenance', - 'UseDbSearch'); + 'UseDbSearch', + 'AllowThirdPartyFraming'); $forms['Sql_queries']['Sql_queries'] = array( 'ShowSQL', 'Confirm',