Skip to content

Commit 7aee8e8

Browse files
committed
Prevent logging tracking failure for obviously malformed idsite or token auth
1 parent 8d15e7a commit 7aee8e8

File tree

4 files changed

+119
-6
lines changed

4 files changed

+119
-6
lines changed

core/Tracker/Request.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,10 @@ protected function authenticateTrackingApi(
206206
if ($this->isAuthenticated) {
207207
Common::printDebug("token_auth is authenticated!");
208208
} else {
209-
StaticContainer::get('Piwik\Tracker\Failures')->logFailure(Failures::FAILURE_ID_NOT_AUTHENTICATED, $this);
209+
if (preg_match('/^\w{28,36}$/', $tokenAuth) || empty($tokenAuth)) {
210+
// only log a failure if the token auth looks partial valid or is completely missing
211+
StaticContainer::get('Piwik\Tracker\Failures')->logFailure(Failures::FAILURE_ID_NOT_AUTHENTICATED, $this);
212+
}
210213
}
211214
} else {
212215
$this->isAuthenticated = true;

core/Tracker/RequestHandlerTrait.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ protected function checkSiteExists(Request $request): void
3131
try {
3232
$request->getIdSite();
3333
} catch (UnexpectedWebsiteFoundException $e) {
34-
// we allow 0... the request will fail anyway as the site won't exist... allowing 0 will help us
35-
// reporting this tracking problem as it is a common issue. Otherwise we would not be able to report
36-
// this problem in tracking failures
37-
StaticContainer::get(Failures::class)->logFailure(Failures::FAILURE_ID_INVALID_SITE, $request);
34+
$idSite = $this->request->getRawParams()['idsite'] ?? null;
35+
if (is_numeric($idSite) && (string)(int)$idSite === (string)$idSite && (int)$idSite >= 0) {
36+
// only log a failure in case the provided idsite was valid positive integer
37+
StaticContainer::get(Failures::class)->logFailure(Failures::FAILURE_ID_INVALID_SITE, $request);
38+
}
39+
3840
throw $e;
3941
}
4042
}

plugins/CoreAdminHome/tests/Fixture/TrackingFailures.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ private function trackData()
4242

4343
$t = self::getTracker($this->idSite, $this->dateTime, $defaultInit = true);
4444
$t->setIp('10.11.12.13');
45-
$t->setTokenAuth('foobar'); // wrong token
45+
$t->setTokenAuth('123456789012345678901234567890ab'); // wrong token
4646
$t->doTrackPageView('Invalid Token');
4747
}
4848
}

tests/PHPUnit/Integration/Tracker/FailuresTest.php

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
namespace Piwik\Tests\Integration\Tracker;
1111

1212
use Piwik\Date;
13+
use Piwik\Exception\InvalidRequestParameterException;
1314
use Piwik\Exception\UnexpectedWebsiteFoundException;
1415
use Piwik\Tests\Framework\Fixture;
1516
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
1617
use Piwik\Tracker\Failures;
1718
use Piwik\Tracker\Request;
19+
use Piwik\Tracker\Visit;
1820

1921
/**
2022
* @group Failures
@@ -301,6 +303,112 @@ public function testRemoveFailuresOlderThanDays()
301303
), $summary);
302304
}
303305

306+
307+
/**
308+
* @dataProvider getInvalidSiteIds
309+
*/
310+
public function testProvidingInvalidSiteIdForTrackingDoesLogFailure(string $idsite)
311+
{
312+
try {
313+
$request = new Request(['idsite' => $idsite, 'rec' => '1', 'url' => 'https://matomo.org/index']);
314+
$visit = new Visit();
315+
$visit->setRequest($request);
316+
$visit->handle();
317+
self::fail('expected exception not raised');
318+
} catch (UnexpectedWebsiteFoundException $e) {
319+
// ignore, as we expect a UnexpectedWebsiteFoundException to be thrown
320+
}
321+
322+
self::assertCount(1, $this->failures->getAllFailures());
323+
}
324+
325+
public function getInvalidSiteIds(): array
326+
{
327+
return [
328+
['4'],
329+
['0'],
330+
['1234'],
331+
];
332+
}
333+
334+
/**
335+
* @dataProvider getMalFormedSiteIds
336+
*/
337+
public function testProvidingMalformedSiteIdForTrackingDoesNotLogFailure(string $idsite)
338+
{
339+
try {
340+
$request = new Request(['idsite' => $idsite, 'rec' => '1', 'url' => 'https://matomo.org/index']);
341+
$visit = new Visit();
342+
$visit->setRequest($request);
343+
$visit->handle();
344+
self::fail('expected exception not raised');
345+
} catch (UnexpectedWebsiteFoundException $e) {
346+
// ignore, as we expect it to be thrown
347+
}
348+
349+
self::assertCount(0, $this->failures->getAllFailures());
350+
}
351+
352+
public function getMalFormedSiteIds(): array
353+
{
354+
return [
355+
[''],
356+
['-4'],
357+
['1"; DROP TABLE'],
358+
['5,6'],
359+
['nan'],
360+
['test5'],
361+
];
362+
}
363+
364+
public function testProvidingInvalidTokenAuthForTrackingDoesLogFailure()
365+
{
366+
try {
367+
$request = new Request(['idsite' => '1', 'rec' => '1', 'url' => 'https://matomo.org/index', 'city' => 'Berlin'], '1d34ghdrg6j33uersadfg34defg342vs');
368+
$visit = new Visit();
369+
$visit->setRequest($request);
370+
$visit->handle();
371+
self::fail('expected exception not raised');
372+
} catch (InvalidRequestParameterException $e) {
373+
// ignore, as we expect that exception
374+
}
375+
376+
self::assertCount(1, $this->failures->getAllFailures());
377+
}
378+
379+
/**
380+
* @dataProvider getMalFormedTokenAuths
381+
*/
382+
public function testProvidingMalformedTokenAuthForTrackingDoesNotLogFailure(string $tokenAuth)
383+
{
384+
try {
385+
$request = new Request(['idsite' => '1', 'rec' => '1', 'url' => 'https://matomo.org/index', 'city' => 'Berlin'], $tokenAuth);
386+
$visit = new Visit();
387+
$visit->setRequest($request);
388+
$visit->handle();
389+
self::fail('expected exception not raised');
390+
} catch (InvalidRequestParameterException $e) {
391+
// ignore, as we expect that exception
392+
}
393+
394+
self::assertCount(0, $this->failures->getAllFailures());
395+
}
396+
397+
public function getMalFormedTokenAuths(): iterable
398+
{
399+
yield 'too short token' => [
400+
'abc',
401+
];
402+
403+
yield 'too long token' => [
404+
'abc2435tgadetb356z2wq3er4gbrnz367634rahne735e5wqergwert245hw45h3gq45h',
405+
];
406+
407+
yield 'token with invalid chars' => [
408+
'33dc3f!536d302$974cccb4b4d2-98f4',
409+
];
410+
}
411+
304412
private function getFailureSummary()
305413
{
306414
$failures = $this->failures->getAllFailures();

0 commit comments

Comments
 (0)