From 7d3cd72db5c23839c750f79cc78ff7bdd3effb4f Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 15 Oct 2024 14:36:10 +0200 Subject: [PATCH 1/3] [!!!][FEATURE] Enrich fingerprint hash with IP address Tracking purely based on device fingerprinting lead to some issues, namely mobile browsers working more towards sandboxing requests so that device hashes end up being the same across the same line of devices. This makes individual tracking unreliable and in the case of Lux leads to some leads that contain several different people in them. This change enriches the fingerprint with the users IP address and hashes it again, leading to a more unique identification value. Negative impact of this change: * (BREAKING) Previously identified users can't be identified anymore, as the calculated fingerprint value has changed. * Compared to before, we now create _more_ unique users than before, as IP addresses (usually) change on the regular for home connections or when switching wi-fi/cellular networks. Related: https://projekte.in2code.de/issues/67221 --- Classes/Domain/Model/Fingerprint.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/Domain/Model/Fingerprint.php b/Classes/Domain/Model/Fingerprint.php index e99f4a00..e09d57f9 100644 --- a/Classes/Domain/Model/Fingerprint.php +++ b/Classes/Domain/Model/Fingerprint.php @@ -7,6 +7,7 @@ use In2code\Lux\Exception\FingerprintMustNotBeEmptyException; use In2code\Lux\Utility\BackendUtility; use In2code\Lux\Utility\EnvironmentUtility; +use In2code\Lux\Utility\IpUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use WhichBrowser\Parser; @@ -52,7 +53,7 @@ public function setValue(string $value): self if (strlen($value) === 33) { $this->setType(self::TYPE_STORAGE); } - $this->value = $value; + $this->value = hash('sha256', $value . IpUtility::getIpAddress()); return $this; } From 884e832005aae50eb105c6d952193bb65d795723 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 15 Oct 2024 14:36:42 +0200 Subject: [PATCH 2/3] [TASK] Add tests for Fingerprint model class Related: https://projekte.in2code.de/issues/67221 --- Tests/Unit/Domain/Model/FingerprintTest.php | 77 +++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Tests/Unit/Domain/Model/FingerprintTest.php diff --git a/Tests/Unit/Domain/Model/FingerprintTest.php b/Tests/Unit/Domain/Model/FingerprintTest.php new file mode 100644 index 00000000..29bc596e --- /dev/null +++ b/Tests/Unit/Domain/Model/FingerprintTest.php @@ -0,0 +1,77 @@ +setValue(random_bytes(32)); + self::assertEquals($fingerprint->getType(), Fingerprint::TYPE_FINGERPRINT); + + $fingerprint->setValue(random_bytes(33)); + self::assertEquals($fingerprint->getType(), Fingerprint::TYPE_STORAGE); + } + + /** + * @return void + * @covers ::setValue + */ + public function testAssertSameHashesWithSameIps(): void + { + $fingerprint = new Fingerprint(); + $identifier = bin2hex(random_bytes(16)); + + $fingerprint->setValue($identifier); + $value1 = $fingerprint->getValue(); + + $fingerprint->setValue($identifier); + $value2 = $fingerprint->getValue(); + + self::assertEquals($value1, $value2); + } + + /** + * @return void + * @covers ::setValue + */ + public function testAssertDifferentHashesWithDifferentIps(): void + { + $fingerprint = new Fingerprint(); + $identifier = bin2hex(random_bytes(16)); + + GeneralUtility::setIndpEnv('REMOTE_ADDR', '192.168.178.1'); + $fingerprint->setValue($identifier); + + $value1 = $fingerprint->getValue(); + + GeneralUtility::setIndpEnv('REMOTE_ADDR', '192.168.178.16'); + $fingerprint->setValue($identifier); + + $value2 = $fingerprint->getValue(); + + self::assertNotEquals($value1, $value2); + } +} From 50e33ab802f29980116fd6168282ebb656ab1125 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 15 Oct 2024 15:35:57 +0200 Subject: [PATCH 3/3] [TASK] Don't hash local storage fingerprints Local storage fingerprint values are already deterministic, they don't require the extra uniqueness factor. Related: https://projekte.in2code.de/issues/67221 --- Classes/Domain/Model/Fingerprint.php | 4 +++- Tests/Unit/Domain/Model/FingerprintTest.php | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Classes/Domain/Model/Fingerprint.php b/Classes/Domain/Model/Fingerprint.php index e09d57f9..d7b8946f 100644 --- a/Classes/Domain/Model/Fingerprint.php +++ b/Classes/Domain/Model/Fingerprint.php @@ -52,8 +52,10 @@ public function setValue(string $value): self } if (strlen($value) === 33) { $this->setType(self::TYPE_STORAGE); + $this->value = $value; + } else { + $this->value = hash('sha256', $value . IpUtility::getIpAddress()); } - $this->value = hash('sha256', $value . IpUtility::getIpAddress()); return $this; } diff --git a/Tests/Unit/Domain/Model/FingerprintTest.php b/Tests/Unit/Domain/Model/FingerprintTest.php index 29bc596e..339123c0 100644 --- a/Tests/Unit/Domain/Model/FingerprintTest.php +++ b/Tests/Unit/Domain/Model/FingerprintTest.php @@ -60,7 +60,7 @@ public function testAssertSameHashesWithSameIps(): void public function testAssertDifferentHashesWithDifferentIps(): void { $fingerprint = new Fingerprint(); - $identifier = bin2hex(random_bytes(16)); + $identifier = random_bytes(32); GeneralUtility::setIndpEnv('REMOTE_ADDR', '192.168.178.1'); $fingerprint->setValue($identifier); @@ -74,4 +74,19 @@ public function testAssertDifferentHashesWithDifferentIps(): void self::assertNotEquals($value1, $value2); } + + /** + * @return void + * @covers ::setValue + */ + public function testAssertNoHashingForStorageType(): void + { + $fingerprint = new Fingerprint(); + $identifier = random_bytes(33); + + $fingerprint->setValue($identifier); + $value = $fingerprint->getValue(); + + self::assertEquals($identifier, $value); + } }