diff options
author | Marc Alexander <admin@m-a-styles.de> | 2017-07-16 11:17:36 +0200 |
---|---|---|
committer | Marc Alexander <admin@m-a-styles.de> | 2017-07-16 11:17:36 +0200 |
commit | 4ed45c4e1276335ff6581a4db58b0173c9905528 (patch) | |
tree | eb0aa1ae403aaadfc876dfe76e97ffb716434e51 /phpBB | |
parent | c99820eb6b13e928fdc2138840e0ec77cd4fe6c9 (diff) | |
parent | 90a77ba9d3e97718e9da7d1ee95ece4e756d26b7 (diff) | |
download | forums-4ed45c4e1276335ff6581a4db58b0173c9905528.tar forums-4ed45c4e1276335ff6581a4db58b0173c9905528.tar.gz forums-4ed45c4e1276335ff6581a4db58b0173c9905528.tar.bz2 forums-4ed45c4e1276335ff6581a4db58b0173c9905528.tar.xz forums-4ed45c4e1276335ff6581a4db58b0173c9905528.zip |
Merge pull request #32 from phpbb/ticket/security-203
[ticket/security-203] Fully validate version check data in version helper
Diffstat (limited to 'phpBB')
-rw-r--r-- | phpBB/includes/functions.php | 5 | ||||
-rw-r--r-- | phpBB/language/en/acp/common.php | 13 | ||||
-rw-r--r-- | phpBB/phpbb/version_helper.php | 108 |
3 files changed, 121 insertions, 5 deletions
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index ba448f3125..84178f74e4 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3442,6 +3442,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 562b446f8a..f5591e7b1e 100644 --- a/phpBB/language/en/acp/common.php +++ b/phpBB/language/en/acp/common.php @@ -417,11 +417,14 @@ $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', - 'VIEW_ADMIN_LOG' => 'View administrator log', - 'VIEW_INACTIVE_USERS' => 'View inactive users', + 'VALUE' => 'Value', + 'VERSIONCHECK_FAIL' => 'Failed to obtain latest version information.', + 'VERSIONCHECK_FORCE_UPDATE' => 'Re-Check version', + '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.', + '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 9dc5a2e7c9..7e5edbf522 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -61,6 +61,23 @@ class version_helper /** @var \phpbb\user */ protected $user; + 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 * @@ -404,9 +421,100 @@ 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 + */ + 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 \RuntimeException($this->user->lang('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 \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_URL')); + } + break; + + case 'version': + if (!empty($value) && !preg_match(get_preg_expression('semantic_version'), $value)) + { + throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_VERSION')); + } + break; + + default: + // Shouldn't be possible to trigger this + throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_ENTRY')); + } + } + } + } + + return $versions_info; + } } |