mirror of
https://github.com/phpbb/phpbb.git
synced 2025-06-10 13:28:55 +00:00
Merge pull request #35 from phpbb/ticket/security-203-rhea
[ticket/security-203] Fully validate version check data in version helper -- Rhea
This commit is contained in:
commit
34e9b4d066
4 changed files with 200 additions and 40 deletions
|
@ -2815,6 +2815,11 @@ function get_preg_expression($mode)
|
||||||
case 'path_remove_dot_trailing_slash':
|
case 'path_remove_dot_trailing_slash':
|
||||||
return '#^(?:(\.)?)+(?:(.+)?)+(?:([\\/\\\])$)#';
|
return '#^(?:(\.)?)+(?:(.+)?)+(?:([\\/\\\])$)#';
|
||||||
break;
|
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 '';
|
return '';
|
||||||
|
|
|
@ -440,16 +440,19 @@ $lang = array_merge($lang, array(
|
||||||
'UPLOAD_DIR_SIZE' => 'Size of posted attachments',
|
'UPLOAD_DIR_SIZE' => 'Size of posted attachments',
|
||||||
'USERS_PER_DAY' => 'Users per day',
|
'USERS_PER_DAY' => 'Users per day',
|
||||||
|
|
||||||
'VALUE' => 'Value',
|
'VALUE' => 'Value',
|
||||||
'VERSIONCHECK_FAIL' => 'Failed to obtain latest version information.',
|
'VERSIONCHECK_FAIL' => 'Failed to obtain latest version information.',
|
||||||
'VERSIONCHECK_FORCE_UPDATE' => 'Re-Check version',
|
'VERSIONCHECK_FORCE_UPDATE' => 'Re-Check version',
|
||||||
'VERSION_CHECK' => 'Version check',
|
'VERSION_CHECK' => 'Version check',
|
||||||
'VERSION_CHECK_EXPLAIN' => 'Checks to see if your phpBB installation is up to date.',
|
'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_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_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.',
|
'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_ADMIN_LOG' => 'View administrator log',
|
||||||
'VIEW_INACTIVE_USERS' => 'View inactive users',
|
'VIEW_INACTIVE_USERS' => 'View inactive users',
|
||||||
|
|
||||||
'WELCOME_PHPBB' => 'Welcome to phpBB',
|
'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).',
|
'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).',
|
||||||
|
|
|
@ -60,6 +60,23 @@ class version_helper
|
||||||
/** @var \phpbb\file_downloader */
|
/** @var \phpbb\file_downloader */
|
||||||
protected $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
|
* Constructor
|
||||||
*
|
*
|
||||||
|
@ -392,9 +409,101 @@ class version_helper
|
||||||
$info['stable'] = (empty($info['stable'])) ? array() : $info['stable'];
|
$info['stable'] = (empty($info['stable'])) ? array() : $info['stable'];
|
||||||
$info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable'];
|
$info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable'];
|
||||||
|
|
||||||
|
$info = $this->validate_versions($info);
|
||||||
|
|
||||||
$this->cache->put($cache_file, $info, 86400); // 24 hours
|
$this->cache->put($cache_file, $info, 86400); // 24 hours
|
||||||
}
|
}
|
||||||
|
|
||||||
return $info;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,8 @@ class version_helper_remote_test extends \phpbb_test_case
|
||||||
public function provider_get_versions()
|
public function provider_get_versions()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array('', false),
|
array('', false, '', 'VERSIONCHECK_FAIL'),
|
||||||
array('foobar', false),
|
array('foobar', false, '', 'VERSIONCHECK_FAIL'),
|
||||||
array('{
|
array('{
|
||||||
"stable": {
|
"stable": {
|
||||||
"1.0": {
|
"1.0": {
|
||||||
|
@ -93,7 +93,7 @@ class version_helper_remote_test extends \phpbb_test_case
|
||||||
"security": false
|
"security": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}', false),
|
}', false, '', 'VERSIONCHECK_FAIL'),
|
||||||
array('{
|
array('{
|
||||||
"stable": {
|
"stable": {
|
||||||
"1.0": {
|
"1.0": {
|
||||||
|
@ -104,26 +104,7 @@ class version_helper_remote_test extends \phpbb_test_case
|
||||||
"security": "<script>alert(\'foo\');</script>"
|
"security": "<script>alert(\'foo\');</script>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}', true, array (
|
}', false, null, 'VERSIONCHECK_INVALID_VERSION'),
|
||||||
'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>',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
array('{
|
array('{
|
||||||
"unstable": {
|
"unstable": {
|
||||||
"1.0": {
|
"1.0": {
|
||||||
|
@ -134,25 +115,87 @@ class version_helper_remote_test extends \phpbb_test_case
|
||||||
"security": "<script>alert(\'foo\');</script>"
|
"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 (
|
}', true, array (
|
||||||
'unstable' => array (
|
'stable' => array (
|
||||||
'1.0' => array (
|
'1.0' => array (
|
||||||
'current' => '1.0.1<script>alert(\'foo\');</script>',
|
'current' => '1.0.1',
|
||||||
'download' => 'https://www.phpbb.com/customise/db/download/104136<script>alert(\'foo\');</script>',
|
'download' => 'https://www.phpbb.com/customise/db/download/104136',
|
||||||
'announcement' => 'https://www.phpbb.com/customise/db/extension/boardrules/<script>alert(\'foo\');</script>',
|
'announcement' => 'https://www.phpbb.com/customise/db/extension/boardrules/',
|
||||||
'eol' => '<script>alert(\'foo\');</script>',
|
'eol' => NULL,
|
||||||
'security' => '<script>alert(\'foo\');</script>',
|
'security' => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'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/',
|
||||||
|
'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
|
* @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);
|
$this->file_downloader->set($input);
|
||||||
|
|
||||||
|
@ -161,7 +204,7 @@ class version_helper_remote_test extends \phpbb_test_case
|
||||||
try {
|
try {
|
||||||
$return = $this->version_helper->get_versions();
|
$return = $this->version_helper->get_versions();
|
||||||
} catch (\phpbb\exception\runtime_exception $e) {
|
} catch (\phpbb\exception\runtime_exception $e) {
|
||||||
$this->assertEquals((string)$e->getMessage(), 'VERSIONCHECK_FAIL');
|
$this->assertEquals((string)$e->getMessage(), $expected_exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Add table
Reference in a new issue