diff options
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | core/Common.php | 26 | ||||
-rw-r--r-- | tests/PHPUnit/Unit/CommonTest.php | 12 |
3 files changed, 42 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dc92b9456..7db5b55f1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,9 @@ These are only recommendations (because we will keep backward compatibility for * If using content tracking, we recommend replacing the following CSS classes should they be used `piwikTrackContent`, `piwikContentPiece`, `piwikContentTarget`, and `piwikContentIgnoreInteraction` with `matomoTrackContent`, `matomoContentPiece`, `matomoContentTarget`, and `matomoContentIgnoreInteraction`. * We also encourage using the `matomo.js` JS tracker file instead of `piwik.js` and `matomo.php` tracker endpoint instead of `piwik.php` endpoint. +#### New APIs +* A new JS tracker method `getMatomoUrl` has been added which replaces `getPiwikUrl`. + ### HTTP APIs #### Breaking changes in HTTP API @@ -130,7 +133,7 @@ These are only recommendations (because we will keep backward compatibility for #### New APIs * A new API `UsersManager.createAppSpecificTokenAuth` has been added to create an app specific token for a user. -* A new JS tracker method `getMatomoUrl` has been added which replaces `getPiwikUrl`. +* A new method `Common::hashEquals` has been added for timing attack safe string comparisons. * Reporting API: It is now possible to apply `hideColumns` recursively to nested values by setting `hideColumnsRecursively=1`. For all `Live` api methods this is the default behaviour. ### Other Breaking changes diff --git a/core/Common.php b/core/Common.php index c53cb9efe1..fd67308062 100644 --- a/core/Common.php +++ b/core/Common.php @@ -283,6 +283,32 @@ class Common } /** + * Timing attack safe string comparison. + * + * @param string $stringA + * @param string $stringB + * @return bool + */ + public static function hashEquals(string $stringA, string $stringB) + { + if (function_exists('hash_equals')) { + return hash_equals($stringA, $stringB); + } + + if (strlen($stringA) !== strlen($stringB)) { + return false; + } + + $result = "\0"; + $stringA^= $stringB; + for ($i = 0; $i < strlen($stringA); $i++) { + $result|= $stringA[$i]; + } + + return $result === "\0"; + } + + /** * Secure wrapper for unserialize, which by default disallows unserializing classes * * @param string $string String to unserialize diff --git a/tests/PHPUnit/Unit/CommonTest.php b/tests/PHPUnit/Unit/CommonTest.php index 5dbdd4112f..d01315778e 100644 --- a/tests/PHPUnit/Unit/CommonTest.php +++ b/tests/PHPUnit/Unit/CommonTest.php @@ -32,6 +32,18 @@ class CommonTest extends TestCase $this->assertEquals(getmypid(), Common::getProcessId()); } + public function test_hashEquals() + { + $this->assertFalse(Common::hashEquals('foo', 'bar')); + $this->assertFalse(Common::hashEquals('foo', 'fo')); + $this->assertFalse(Common::hashEquals('foo', 'fooo')); + $this->assertFalse(Common::hashEquals('foo', 'foa')); + $this->assertFalse(Common::hashEquals('foo', 'eoo')); + $this->assertFalse(Common::hashEquals('foo', '')); + $this->assertFalse(Common::hashEquals('', 'bar')); + $this->assertTrue(Common::hashEquals('foo', 'foo')); + } + /** * Dataprovider for testSanitizeInputValues */ |