diff options
author | Marc Alexander <admin@m-a-styles.de> | 2017-07-16 15:29:35 +0200 |
---|---|---|
committer | Marc Alexander <admin@m-a-styles.de> | 2017-07-16 15:29:35 +0200 |
commit | 34e9b4d0660151fffe60291ad4c51359af3c7dd9 (patch) | |
tree | 12e22b61c7ef97baf7661109da70d0f927a989ce | |
parent | 6f897568daef94545e61f361b2b4f77023a50a28 (diff) | |
parent | d63b644b2b976b6b067f779af91cc7699c4bd522 (diff) | |
download | forums-34e9b4d0660151fffe60291ad4c51359af3c7dd9.tar forums-34e9b4d0660151fffe60291ad4c51359af3c7dd9.tar.gz forums-34e9b4d0660151fffe60291ad4c51359af3c7dd9.tar.bz2 forums-34e9b4d0660151fffe60291ad4c51359af3c7dd9.tar.xz forums-34e9b4d0660151fffe60291ad4c51359af3c7dd9.zip |
Merge pull request #35 from phpbb/ticket/security-203-rhea
[ticket/security-203] Fully validate version check data in version helper -- Rhea
-rw-r--r-- | phpBB/includes/functions.php | 5 | ||||
-rw-r--r-- | phpBB/language/en/acp/common.php | 19 | ||||
-rw-r--r-- | phpBB/phpbb/version_helper.php | 109 | ||||
-rw-r--r-- | tests/version/version_helper_remote_test.php | 105 |
4 files changed, 199 insertions, 39 deletions
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 3dabd1b46e..6c15c14300 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -2815,6 +2815,11 @@ function get_preg_expression($mode) case 'path_remove_dot_trailing_slash': return '#^(?:(\.)?)+(?:(.+)?)+(?:([\\/\\\])$)#'; break; + + case 'semantic_version': + // Regular expression to match semantic versions by http://rgxdb.com/ + return '/(?<=^[Vv]|^)(?:(?<major>(?:0|[1-9](?:(?:0|[1-9])+)*))[.](?<minor>(?:0|[1-9](?:(?:0|[1-9])+)*))[.](?<patch>(?:0|[1-9](?:(?:0|[1-9])+)*))(?:-(?<prerelease>(?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:0|[1-9](?:(?:0|[1-9])+)*))(?:[.](?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:0|[1-9](?:(?:0|[1-9])+)*)))*))?(?:[+](?<build>(?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:(?:0|[1-9])+))(?:[.](?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:(?:0|[1-9])+)))*))?)$/'; + break; } return ''; diff --git a/phpBB/language/en/acp/common.php b/phpBB/language/en/acp/common.php index 63235c01d8..de5039f047 100644 --- a/phpBB/language/en/acp/common.php +++ b/phpBB/language/en/acp/common.php @@ -440,16 +440,19 @@ $lang = array_merge($lang, array( 'UPLOAD_DIR_SIZE' => 'Size of posted attachments', 'USERS_PER_DAY' => 'Users per day', - 'VALUE' => 'Value', - 'VERSIONCHECK_FAIL' => 'Failed to obtain latest version information.', - 'VERSIONCHECK_FORCE_UPDATE' => 'Re-Check version', - 'VERSION_CHECK' => 'Version check', - 'VERSION_CHECK_EXPLAIN' => 'Checks to see if your phpBB installation is up to date.', + 'VALUE' => 'Value', + 'VERSIONCHECK_FAIL' => 'Failed to obtain latest version information.', + 'VERSIONCHECK_FORCE_UPDATE' => 'Re-Check version', + 'VERSION_CHECK' => 'Version check', + 'VERSION_CHECK_EXPLAIN' => 'Checks to see if your phpBB installation is up to date.', + 'VERSIONCHECK_INVALID_ENTRY' => 'Latest version information contains an unsupported entry.', + 'VERSIONCHECK_INVALID_URL' => 'Latest version information contains invalid URL.', + 'VERSIONCHECK_INVALID_VERSION' => 'Latest version information contains an invalid version.', 'VERSION_NOT_UP_TO_DATE_ACP' => 'Your phpBB installation is not up to date.<br />Below is a link to the release announcement, which contains more information as well as instructions on updating.', 'VERSION_NOT_UP_TO_DATE_TITLE' => 'Your phpBB installation is not up to date.', - 'VERSION_UP_TO_DATE_ACP' => 'Your phpBB installation is up to date. There are no updates available at this time.', - 'VIEW_ADMIN_LOG' => 'View administrator log', - 'VIEW_INACTIVE_USERS' => 'View inactive users', + 'VERSION_UP_TO_DATE_ACP' => 'Your phpBB installation is up to date. There are no updates available at this time.', + 'VIEW_ADMIN_LOG' => 'View administrator log', + 'VIEW_INACTIVE_USERS' => 'View inactive users', 'WELCOME_PHPBB' => 'Welcome to phpBB', 'WRITABLE_CONFIG' => 'Your config file (config.php) is currently world-writable. We strongly encourage you to change the permissions to 640 or at least to 644 (for example: <a href="http://en.wikipedia.org/wiki/Chmod" rel="external">chmod</a> 640 config.php).', diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php index bb15dd1a74..a73fbfbfbe 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -60,6 +60,23 @@ class version_helper /** @var \phpbb\file_downloader */ protected $file_downloader; + protected $version_schema = array( + 'stable' => array( + 'current' => 'version', + 'download' => 'url', + 'announcement' => 'url', + 'eol' => 'url', + 'security' => 'bool', + ), + 'unstable' => array( + 'current' => 'version', + 'download' => 'url', + 'announcement' => 'url', + 'eol' => 'url', + 'security' => 'bool', + ), + ); + /** * Constructor * @@ -392,9 +409,101 @@ class version_helper $info['stable'] = (empty($info['stable'])) ? array() : $info['stable']; $info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable']; + $info = $this->validate_versions($info); + $this->cache->put($cache_file, $info, 86400); // 24 hours } return $info; } + + /** + * Validate versions info input + * + * @param array $versions_info Decoded json data array. Will be modified + * and cleaned by this method + * + * @return array Versions info array + * @throws version_check_exception + */ + public function validate_versions($versions_info) + { + $array_diff = array_diff_key($versions_info, array($this->version_schema)); + + // Remove excessive data + if (count($array_diff) > 0) + { + $old_versions_info = $versions_info; + $versions_info = array( + 'stable' => !empty($old_versions_info['stable']) ? $old_versions_info['stable'] : array(), + 'unstable' => !empty($old_versions_info['unstable']) ? $old_versions_info['unstable'] : array(), + ); + unset($old_versions_info); + } + + foreach ($versions_info as $stability_type => &$versions_data) + { + foreach ($versions_data as $branch => &$version_data) + { + if (!preg_match('/^[0-9a-z\-\.]+$/i', $branch)) + { + unset($versions_data[$branch]); + continue; + } + + $stability_diff = array_diff_key($version_data, $this->version_schema[$stability_type]); + + if (count($stability_diff) > 0) + { + $old_version_data = $version_data; + $version_data = array(); + foreach ($this->version_schema[$stability_type] as $key => $value) + { + if (isset($old_version_data[$key])) + { + $version_data[$key] = $old_version_data[$key]; + } + } + unset($old_version_data); + } + + foreach ($version_data as $key => &$value) + { + if (!isset($this->version_schema[$stability_type][$key])) + { + unset($version_data[$key]); + throw new version_check_exception('VERSIONCHECK_INVALID_ENTRY'); + } + + switch ($this->version_schema[$stability_type][$key]) + { + case 'bool': + $value = (bool) $value; + break; + + case 'url': + if (!empty($value) && !preg_match('#^' . get_preg_expression('url') . '$#iu', $value) && + !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $value)) + { + throw new version_check_exception('VERSIONCHECK_INVALID_URL'); + } + break; + + case 'version': + if (!empty($value) && !preg_match(get_preg_expression('semantic_version'), $value)) + { + throw new version_check_exception('VERSIONCHECK_INVALID_VERSION'); + } + break; + + default: + // Shouldn't be possible to trigger this + throw new version_check_exception('VERSIONCHECK_INVALID_ENTRY'); + } + } + } + } + + return $versions_info; + } } diff --git a/tests/version/version_helper_remote_test.php b/tests/version/version_helper_remote_test.php index fa383d487f..35c3d92a3a 100644 --- a/tests/version/version_helper_remote_test.php +++ b/tests/version/version_helper_remote_test.php @@ -51,8 +51,8 @@ class version_helper_remote_test extends \phpbb_test_case public function provider_get_versions() { return array( - array('', false), - array('foobar', false), + array('', false, '', 'VERSIONCHECK_FAIL'), + array('foobar', false, '', 'VERSIONCHECK_FAIL'), array('{ "stable": { "1.0": { @@ -93,7 +93,7 @@ class version_helper_remote_test extends \phpbb_test_case "security": false } } -}', false), +}', false, '', 'VERSIONCHECK_FAIL'), array('{ "stable": { "1.0": { @@ -104,26 +104,7 @@ class version_helper_remote_test extends \phpbb_test_case "security": "<script>alert(\'foo\');</script>" } } -}', true, array ( - 'stable' => array ( - '1.0' => array ( - 'current' => '1.0.1<script>alert(\'foo\');</script>', - 'download' => 'https://www.phpbb.com/customise/db/download/104136<script>alert(\'foo\');</script>', - 'announcement' => 'https://www.phpbb.com/customise/db/extension/boardrules/<script>alert(\'foo\');</script>', - 'eol' => '<script>alert(\'foo\');</script>', - 'security' => '<script>alert(\'foo\');</script>', - ), - ), - 'unstable' => array ( - '1.0' => array ( - 'current' => '1.0.1<script>alert(\'foo\');</script>', - 'download' => 'https://www.phpbb.com/customise/db/download/104136<script>alert(\'foo\');</script>', - 'announcement' => 'https://www.phpbb.com/customise/db/extension/boardrules/<script>alert(\'foo\');</script>', - 'eol' => '<script>alert(\'foo\');</script>', - 'security' => '<script>alert(\'foo\');</script>', - ), - ), - )), +}', false, null, 'VERSIONCHECK_INVALID_VERSION'), array('{ "unstable": { "1.0": { @@ -134,25 +115,87 @@ class version_helper_remote_test extends \phpbb_test_case "security": "<script>alert(\'foo\');</script>" } } +}', false, null, 'VERSIONCHECK_INVALID_VERSION'), + array('{ + "unstable": { + "1.0<script>alert(\'foo\');</script>": { + "current": "1.0.1", + "download": "https://www.phpbb.com/customise/db/download/104136", + "announcement": "https://www.phpbb.com/customise/db/extension/boardrules/", + "eol": "", + "security": "" + } + } +}', false, array('stable' => array(), 'unstable' => array()), 'VERSIONCHECK_INVALID_VERSION'), + array('{ + "\"\n<script>alert(\'foo\');</script>\n": "test", + "stable": { + "1.0": { + "current": "1.0.1", + "download": "https://www.phpbb.com/customise/db/download/104136", + "announcement": "https://www.phpbb.com/customise/db/extension/boardrules/", + "eol": null, + "security": false + } + } }', true, array ( + 'stable' => array ( + '1.0' => array ( + 'current' => '1.0.1', + 'download' => 'https://www.phpbb.com/customise/db/download/104136', + 'announcement' => 'https://www.phpbb.com/customise/db/extension/boardrules/', + 'eol' => NULL, + 'security' => false, + ), + ), 'unstable' => array ( '1.0' => array ( - 'current' => '1.0.1<script>alert(\'foo\');</script>', - 'download' => 'https://www.phpbb.com/customise/db/download/104136<script>alert(\'foo\');</script>', - 'announcement' => 'https://www.phpbb.com/customise/db/extension/boardrules/<script>alert(\'foo\');</script>', - 'eol' => '<script>alert(\'foo\');</script>', - 'security' => '<script>alert(\'foo\');</script>', + 'current' => '1.0.1', + 'download' => 'https://www.phpbb.com/customise/db/download/104136', + 'announcement' => 'https://www.phpbb.com/customise/db/extension/boardrules/', + 'eol' => NULL, + 'security' => false, ), ), - 'stable' => array(), )), + array('{ + "unstable": { + "1.0": { + "current": "1.0.1", + "download": "https://www.phpbb.com/customise/db/download/104136", + "announcement": "https://www.phpbb.com/customise/db/extension/boardrules/", + "eol": null, + "security": false, + "foobar": "<script>alert(\'test\');<script>" + } + } +}', true, array('stable' => array(), 'unstable' => array('1.0' => array( + 'current' => '1.0.1', + 'download' => 'https://www.phpbb.com/customise/db/download/104136', + 'announcement' => 'https://www.phpbb.com/customise/db/extension/boardrules/', + 'security' => false, + ))), 'VERSIONCHECK_INVALID_ENTRY'), + array('{ + "unstable": { + "1.0": { + "current<script>alert(\'foo\');</script>": "1.0.1", + "download2": "https://www.phpbb.com/customise/db/download/104136", + "bannouncement": "https://www.phpbb.com/customise/db/extension/boardrules/", + "eol": null, + "security": false, + "foobar": "<script>alert(\'test\');<script>" + } + } +}', true, array('stable' => array(), 'unstable' => array('1.0' => array( + 'security' => false, + ))), 'VERSIONCHECK_INVALID_ENTRY'), ); } /** * @dataProvider provider_get_versions */ - public function test_get_versions($input, $valid_data, $expected_return = '') + public function test_get_versions($input, $valid_data, $expected_return = '', $expected_exception = '') { $this->file_downloader->set($input); @@ -161,7 +204,7 @@ class version_helper_remote_test extends \phpbb_test_case try { $return = $this->version_helper->get_versions(); } catch (\phpbb\exception\runtime_exception $e) { - $this->assertEquals((string)$e->getMessage(), 'VERSIONCHECK_FAIL'); + $this->assertEquals((string)$e->getMessage(), $expected_exception); } } else |