diff --git a/ChangeLog b/ChangeLog index 506177868c..9be0b27dba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,6 +62,10 @@ phpMyAdmin - ChangeLog - issue #12012 Column definition with default value and comment in CREATE TABLE expoerted faulty. - issue #12020 New statement but no delimiter and unexpected token with REPLACE. - issue #12029 Fixed incorrect usage of SQL parser context in SQL export +- issue [security] XSS vulnerability in SQL parser, see PMASA-2016-10. +- issue [security] Multiple XSS vulnerabilities, see PMASA-2016-11. +- issue [security] Multiple XSS vulnerabilities, see PMASA-2016-12. +- issue [security] Vulnerability allowing man-in-the-middle attack on API call to GitHub, see PMASA-2016-13. - issue #12048 Fixed inclusion of gettext library from SQL parser 4.5.5.0 (2016-02-22) diff --git a/db_central_columns.php b/db_central_columns.php index 493b8937ef..19cef7335e 100644 --- a/db_central_columns.php +++ b/db_central_columns.php @@ -94,7 +94,7 @@ if (isset($_REQUEST['total_rows']) && $_REQUEST['total_rows']) { } else { $total_rows = PMA_getCentralColumnsCount($db); } -if (isset($_REQUEST['pos'])) { +if (PMA_isValid($_REQUEST['pos'], 'integer')) { $pos = $_REQUEST['pos']; } else { $pos = 0; diff --git a/file_echo.php b/file_echo.php index 0d65f0f7be..7c9374b9eb 100644 --- a/file_echo.php +++ b/file_echo.php @@ -64,12 +64,16 @@ if (isset($_REQUEST['filename']) && isset($_REQUEST['image'])) { } else if (isset($_REQUEST['monitorconfig'])) { /* For monitor chart config export */ - PMA_downloadHeader('monitor.cfg', 'application/force-download'); + PMA_downloadHeader('monitor.cfg', 'application/json; charset=UTF-8'); + header('X-Content-Type-Options: nosniff'); + echo urldecode($_REQUEST['monitorconfig']); } else if (isset($_REQUEST['import'])) { /* For monitor chart config import */ - header('Content-type: text/plain'); + header('Content-Type: application/json; charset=UTF-8'); + header('X-Content-Type-Options: nosniff'); + if (!file_exists($_FILES['file']['tmp_name'])) { exit(); } diff --git a/js/functions.js b/js/functions.js index ddcfc5636b..c7a1f23a38 100644 --- a/js/functions.js +++ b/js/functions.js @@ -340,6 +340,24 @@ function escapeHtml(unsafe) { } } +function escapeJsString(unsafe) { + if (typeof(unsafe) != 'undefined') { + return unsafe + .toString() + .replace("\000", '') + .replace('\\', '\\\\') + .replace('\'', '\\\'') + .replace("'", "\\\'") + .replace('"', '\"') + .replace(""", "\"") + .replace("\n", '\n') + .replace("\r", '\r') + .replace(/<\/script/gi, '" + sql_query + "\n"; + var new_content = "\n"; new_content += getForeignKeyCheckboxLoader(); new_content += "\n"; new_content += "\n"; diff --git a/js/normalization.js b/js/normalization.js index 48abc71554..da1dbfe6e0 100644 --- a/js/normalization.js +++ b/js/normalization.js @@ -82,7 +82,7 @@ function goTo2NFStep1() { $("#mainContent #extra").html(data.extra); $("#mainContent #newCols").html(''); if (data.subText !== '') { - $('.tblFooters').html(''); + $('.tblFooters').html(''); } else { if (normalizeto === '3nf') { $("#mainContent #newCols").html(PMA_messages.strToNextStep); @@ -128,7 +128,7 @@ function goToStep4() $("#mainContent #newCols").html(''); $('.tblFooters').html(''); for(var pk in primary_key) { - $("#extra input[value='" + primary_key[pk] + "']").attr("disabled","disabled"); + $("#extra input[value='" + escapeJsString(primary_key[pk]) + "']").attr("disabled","disabled"); } } ); @@ -153,7 +153,7 @@ function goToStep3() $('.tblFooters').html(''); primary_key = $.parseJSON(data.primary_key); for(var pk in primary_key) { - $("#extra input[value='" + primary_key[pk] + "']").attr("disabled","disabled"); + $("#extra input[value='" + escapeJsString(primary_key[pk]) + "']").attr("disabled","disabled"); } } ); @@ -638,7 +638,7 @@ AJAX.registerOnload('normalization.js', function() { ''; $("#newCols").html(confirmStr); $('.tblFooters').html('' + - ''); + ''); } }); $("#mainContent p").on("click", "#createPrimaryKey", function(event) { diff --git a/libraries/Config.php b/libraries/Config.php index 9edf47725b..147bc5c1a6 100644 --- a/libraries/Config.php +++ b/libraries/Config.php @@ -725,8 +725,8 @@ class Config Util::configureCurl($handle); curl_setopt($handle, CURLOPT_FOLLOWLOCATION, 0); curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 0); - curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, '2'); + curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, '1'); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($handle, CURLOPT_TIMEOUT, 5); curl_setopt($handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); diff --git a/libraries/controllers/table/TableSearchController.php b/libraries/controllers/table/TableSearchController.php index f58c9c93fc..f8c7dcb48b 100644 --- a/libraries/controllers/table/TableSearchController.php +++ b/libraries/controllers/table/TableSearchController.php @@ -393,7 +393,11 @@ class TableSearchController extends TableController return; } $key = array_search($field, $this->_columnNames); - $properties = $this->getColumnProperties($_REQUEST['it'], $key); + $search_index = 0; + if (PMA_isValid($_REQUEST['it'], 'integer')) { + $search_index = $_REQUEST['it']; + } + $properties = $this->getColumnProperties($search_index, $key); $this->response->addJSON( 'field_type', htmlspecialchars($properties['type']) ); diff --git a/libraries/server_privileges.lib.php b/libraries/server_privileges.lib.php index e17d5160a8..50c39843e6 100644 --- a/libraries/server_privileges.lib.php +++ b/libraries/server_privileges.lib.php @@ -3635,7 +3635,7 @@ function PMA_getUsersOverview($result, $db_rights, $pmaThemeImage, $text_dir) __('Export'), 'b_tblexport.png', 'export' ); $html_output .= ''; + . 'value="' . (isset($_GET['initial']) ? htmlspecialchars($_GET['initial']) : '') . '" />'; $html_output .= '' . '
'; diff --git a/normalization.php b/normalization.php index c6601ff40d..e732cff169 100644 --- a/normalization.php +++ b/normalization.php @@ -72,7 +72,7 @@ $scripts = $header->getScripts(); $scripts->addFile('normalization.js'); $scripts->addFile('jquery/jquery.uitablefilter.js'); $normalForm = '1nf'; -if (isset($_REQUEST['normalizeTo'])) { +if (PMA_isValid($_REQUEST['normalizeTo'], array('1nf', '2nf', '3nf'))) { $normalForm = $_REQUEST['normalizeTo']; } if (isset($_REQUEST['createNewTables2NF'])) { diff --git a/templates/database/structure/sortable_header.phtml b/templates/database/structure/sortable_header.phtml index e270666645..42951bc6b0 100644 --- a/templates/database/structure/sortable_header.phtml +++ b/templates/database/structure/sortable_header.phtml @@ -51,16 +51,21 @@ if ($requested_sort == $sort) { } $_url_params = array( 'db' => $_REQUEST['db'], + 'pos' => 0, // We set the position back to 0 every time they sort. + 'sort' => $sort, + 'sort_order' => $future_sort_order, ); -$url = 'db_structure.php' . PMA\libraries\URL::getCommon($_url_params); -// We set the position back to 0 every time they sort. -$url .= "&pos=0&sort=$sort&sort_order=$future_sort_order"; -if (! empty($_REQUEST['tbl_type'])) { - $url .= "&tbl_type=" . $_REQUEST['tbl_type']; + +if (PMA_isValid($_REQUEST['tbl_type'], array('view', 'table'))) { + $_url_params['tbl_type'] = $_REQUEST['tbl_type']; } if (! empty($_REQUEST['tbl_group'])) { - $url .= "&tbl_group=" . $_REQUEST['tbl_group']; + $_url_params['tbl_group'] = $_REQUEST['tbl_group']; } + +$url = 'db_structure.php' . PMA_URL_getCommon($_url_params); + +echo PMA_Util::linkOrButton( echo PMA\libraries\Util::linkOrButton( $url, $title . $order_img, $order_link_params ); diff --git a/templates/table/search/input_box.phtml b/templates/table/search/input_box.phtml index 6f4080c9f4..83c68acd84 100644 --- a/templates/table/search/input_box.phtml +++ b/templates/table/search/input_box.phtml @@ -20,7 +20,7 @@ if ($_foreigners - value="" + value="" /> " selected> @@ -97,6 +98,15 @@ if ($_foreigners + + @@ -126,7 +136,11 @@ if ($_foreigners +<<<<<<< HEAD value="" +======= + value="" +>>>>>>> MAINT_4_5_5-security /> diff --git a/templates/table/search/rows_zoom.phtml b/templates/table/search/rows_zoom.phtml index 7ddaff8053..0dcb712a04 100644 --- a/templates/table/search/rows_zoom.phtml +++ b/templates/table/search/rows_zoom.phtml @@ -68,7 +68,7 @@ for ($i = 0; $i < 4; $i++): ?> - + diff --git a/test/classes/ConfigTest.php b/test/classes/ConfigTest.php index 944315f0da..68df643eff 100644 --- a/test/classes/ConfigTest.php +++ b/test/classes/ConfigTest.php @@ -49,6 +49,7 @@ class ConfigTest extends PMATestCase $GLOBALS['server'] = 0; $_SESSION['is_git_revision'] = true; $GLOBALS['PMA_Config'] = new PMA\libraries\Config(CONFIG_FILE); + $GLOBALS['cfg']['ProxyUrl'] = ''; //for testing file permissions $this->permTestObj = new PMA\libraries\Config("./config.sample.inc.php"); @@ -886,14 +887,19 @@ class ConfigTest extends PMATestCase $this->markTestSkipped('Missing curl extension!'); } $this->assertTrue( - $this->object->checkHTTP("http://www.phpmyadmin.net/test/data") + $this->object->checkHTTP("https://www.phpmyadmin.net/test/data") ); $this->assertContains( "TEST DATA", - $this->object->checkHTTP("http://www.phpmyadmin.net/test/data", true) + $this->object->checkHTTP("https://www.phpmyadmin.net/test/data", true) ); $this->assertFalse( - $this->object->checkHTTP("http://www.phpmyadmin.net/test/nothing") + $this->object->checkHTTP("https://www.phpmyadmin.net/test/nothing") + ); + // Use rate limit API as it's not subject to rate limiting + $this->assertContains( + '"resources"', + $this->object->checkHTTP("https://api.github.com/rate_limit", true) ); } }