Skip to content

Commit

Permalink
Limit GeoIP downloads to certain hosts only (#17097)
Browse files Browse the repository at this point in the history
* Limit GeoIP downloads to certains hosts only

* make geoip error message translatable

* apply review feedback
  • Loading branch information
sgiehl committed Jan 19, 2021
1 parent 4e55cd0 commit 1a05313
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,12 @@ This is the Developer Changelog for Matomo platform developers. All changes in o

The Product Changelog at **[matomo.org/changelog](https://matomo.org/changelog)** lets you see more details about any Matomo release, such as the list of new guides and FAQs, security fixes, and links to all closed issues.

## Matomo 4.2.0

### New config.ini.php settings

* A config setting `geolocation_download_from_trusted_hosts` was introduced. Downloading GeoIP databases will now be limited to those configured hosts only.

## Matomo 4.1.1

### Changed config.ini.php settings
Expand Down
5 changes: 5 additions & 0 deletions config/global.ini.php
Expand Up @@ -404,6 +404,11 @@
; This can add an additional layer of security as SERVER_NAME can not be manipulated by sending custom host headers when configure correctly.
host_validation_use_server_name = 0

; This list defines the hostnames that a valid sources to download GeoIP databases from. Subdomains of those hostnames will be accepted automatically.
geolocation_download_from_trusted_hosts[] = maxmind.com
geolocation_download_from_trusted_hosts[] = db-ip.com
geolocation_download_from_trusted_hosts[] = ip2location.com

; Session garbage collection on (as on some operating systems, i.e. Debian, it may be off by default)
session_gc_probability = 1

Expand Down
40 changes: 36 additions & 4 deletions plugins/GeoIp2/GeoIP2AutoUpdater.php
Expand Up @@ -11,6 +11,7 @@
use Exception;
use GeoIp2\Database\Reader;
use Piwik\Common;
use Piwik\Config;
use Piwik\Container\StaticContainer;
use Piwik\Date;
use Piwik\Http;
Expand Down Expand Up @@ -424,9 +425,9 @@ public static function setUpdaterOptions($options)

$url = $options[$optionKey];
$url = self::removeDateFromUrl($url);
if (!empty($url) && strpos(Common::mb_strtolower($url), 'https://') !== 0 && strpos(Common::mb_strtolower($url), 'http://') !== 0) {
throw new Exception('Invalid download URL for geoip ' . $optionKey . ': ' . $url);
}

self::checkGeoIPUpdateUrl($url);

Option::set($optionName, $url);
}

Expand All @@ -452,6 +453,37 @@ public static function setUpdaterOptions($options)
}
}

protected static function checkGeoIPUpdateUrl($url)
{
if (empty($url)) {
return;
}

$parsedUrl = @parse_url($url);
$schema = $parsedUrl['scheme'] ?? '';
$host = $parsedUrl['host'] ?? '';

if (empty($schema) || empty($host) || !in_array(Common::mb_strtolower($schema), ['http', 'https'])) {
throw new Exception(Piwik::translate('GeoIp2_MalFormedUpdateUrl', '<i>'.$url.'</i>'));
}

$validHosts = Config::getInstance()->General['geolocation_download_from_trusted_hosts'];
$isValidHost = false;

foreach ($validHosts as $validHost) {
if (preg_match('/(^|\.)' . preg_quote($validHost) . '$/i', $host)) {
$isValidHost = true;
break;
}
}

if (true !== $isValidHost) {
throw new Exception(Piwik::translate('GeoIp2_InvalidGeoIPUpdateHost', [
'<i>'.$url.'</i>', '<i>'.implode(', ', $validHosts).'</i>', '<i>geolocation_download_from_trusted_hosts</i>'
]));
}
}

/**
* Returns true if the auto-updater is setup to update at least one type of
* database. False if otherwise.
Expand Down Expand Up @@ -642,7 +674,7 @@ protected function performRedundantDbChecks($logErrors = true)
}

// get the current filename for the DB and an available new one to rename it to
list($oldPath, $newPath) = $this->getOldAndNewPathsForBrokenDb($customNames[$type]);
[$oldPath, $newPath] = $this->getOldAndNewPathsForBrokenDb($customNames[$type]);

// rename the DB so tracking will not fail
if ($oldPath !== false
Expand Down
2 changes: 2 additions & 0 deletions plugins/GeoIp2/lang/en.json
Expand Up @@ -44,6 +44,8 @@
"LocationProviderDesc_Php_WithExtension": "This location provider is speeded up by the installed %1$smaxminddb%2$s extension.",
"LocationProviderDesc_ServerModule": "This location provider uses the GeoIP 2 module that has been installed in your HTTP server. This provider is fast and accurate, but %1$scan only be used with normal browser tracking.%2$s",
"LocationProviderDesc_ServerModule2": "If you have to import log files or do something else that requires setting IP addresses, use the %3$sPHP GeoIP 2 implementation%4$s and install %1$smaxminddb extension%2$s.",
"MalFormedUpdateUrl": "The url %1$s seems invalid. Please ensure to input a valid url starting with http:// or https://",
"InvalidGeoIPUpdateHost": "The host of the GeoIP update url %1$s is not trusted. To allow downloading GeoIP updates from hosts other than %2$s please adjust the setting for %3$s in config. ",
"NotManagingGeoIPDBs": "Matomo is currently not managing any DBIP or MaxMind databases.",
"UnsupportedArchiveType": "Encountered unsupported archive type %1$s.",
"UpdaterHasNotBeenRun": "The updater has never been run.",
Expand Down
45 changes: 43 additions & 2 deletions plugins/GeoIp2/tests/Unit/GeoIP2AutoUpdaterTest.php
Expand Up @@ -8,8 +8,7 @@

namespace Piwik\Plugins\GeoIp2\tests\Unit;

use Piwik\DataTable;
use Piwik\DataTable\Row;
use Piwik\Config;
use Piwik\Plugins\GeoIp2\GeoIP2AutoUpdater;

class public_GeoIP2AutoUpdater extends GeoIP2AutoUpdater
Expand All @@ -23,6 +22,10 @@ public function fetchPaidDbIpUrl($url)
{
return parent::fetchPaidDbIpUrl($url);
}

public static function checkGeoIPUpdateUrl($url) {
return parent::checkGeoIPUpdateUrl($url);
}
}

/**
Expand Down Expand Up @@ -146,4 +149,42 @@ public function testFetchPaidUrlForFullJson()

$this->assertEquals('https://download.db-ip.com/key/ad446bf4cb9a44e4fff3f215deabc710f12f3.mmdb', $determinedUrl);
}

/**
* @dataProvider getUpdaterUrlOptions
*/
public function testInvalidUpdateOptions($url, $valid)
{
if (!$valid) {
$this->expectException(\Exception::class);
} else {
$this->expectNotToPerformAssertions();
}
public_GeoIP2AutoUpdater::checkGeoIPUpdateUrl($url);
}

public function getUpdaterUrlOptions()
{
return [
['https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-ASN&license_key=YOUR_LICENSE_KEY&suffix=tar.gz', true],
['https://download.db-ip.com/key/ad446bf4cb9a44e4fff3f215deabc710f12f3.mmdb', true],
['https://download.db-ip.com/free/dbip-city-lite-2020-01.mmdb.gz', true],
['https://db-ip.com/account/ad446bf4cb9a44e5ff3f215deabc710f12f3/db/ip-to-country/mmdb', true],
['https://www.ip2location.com/download/?token={DOWNLOAD_TOKEN}&file={DATABASE_CODE}', true],
['https://download.maxmind.com.fake.org/app/geoip_download?edition_id=GeoLite2-ASN&license_key=YOUR_LICENSE_KEY&suffix=tar.gz', false],
['https://fakemaxmind.com/ad446bf4cb9a44e4fff3f215deabc710f12f3.mmdb', false],
['https://fake-db-ip.com/account/ad446bf4cb9a44e5ff3f215deabc710f12f3/db/ip-to-country/mmdb', false],
['http://my.custom.host/download.tar.gz', false],
['phar://local/input.file', false],
['ftp://db-ip.com/account/ad446bf4cb9a44e4fff3f215deabc710f12f3/db/ip-to-country/mmdb', false],
['http://matomo.org/download/geoip.mmdb', false],
];
}

public function testsAdditionalGeoIPHostConfig()
{
$this->expectNotToPerformAssertions();
Config::getInstance()->General['geolocation_download_from_trusted_hosts'][] = 'matomo.org';
public_GeoIP2AutoUpdater::checkGeoIPUpdateUrl('http://matomo.org/download/geoip.mmdb');
}
}

0 comments on commit 1a05313

Please sign in to comment.