1
0
mirror of https://github.com/phpbb/phpbb.git synced 2025-08-08 17:56:52 +02:00

[ticket/security-203] Fully validate version check data in version helper

This will also take care of SECURITY-204 as it's the same underlying issue.
Admins still need to ensure they don't visit malicious sites for URLs
provided by extensions.

SECURITY-203
This commit is contained in:
Marc Alexander
2016-12-26 22:01:51 +01:00
parent 97a0f49be4
commit 658820654f
4 changed files with 185 additions and 40 deletions

View File

@@ -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
*
@@ -298,9 +315,99 @@ class version_helper
$info['stable'] = (empty($info['stable'])) ? array() : $info['stable'];
$info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable'];
$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
*/
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-9]+\.[0-9]+$/', $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]) || $old_version_data[$key] === null)
{
$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))
{
$value = '';
throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_URL'));
}
break;
case 'version':
$value = $value ?: '';
if (!preg_match(get_preg_expression('semantic_version'), $value))
{
$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'));
}
}
}
}
}
}