@anonympins/fingerprint 0.6.5 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +2 -2
- package/package.json +4 -1
- package/src/js/fingerprint.client.obfuscated.js +1 -1
- package/src/js/fingerprint.js +239 -48
- package/src/js/gpu_pow.solver.js +3 -2
- package/src/js/pow.solver.inline.js +128 -2
- package/src/js/pow.solver.js +85 -0
- package/src/js/problem-manager.js +16 -1
- package/src/js/tests/cross_parity.test.js +2 -2
- package/src/js/tests/fingerprint.test.js +12 -3
- package/src/js/tests/ip-reputation.test.js +1 -1
- package/src/js/tests/quicFingerprint.test.js +21 -10
- package/src/js/upow-model-task.js +114 -0
- package/src/php/Challenge/ChallengeUtils.php +1 -1
- package/src/php/Config/SecurityProfiles.php +6 -6
- package/src/php/FingerprintEngine.php +4 -4
- package/src/php/Optimization/FunctionRegistry.php +1 -1
- package/src/php/Optimization/OptimizationOperators.php +13 -0
- package/src/php/ProblemManager.php +22 -0
- package/src/php/Tests/ChallengeUtilsTest.php +3 -2
- package/src/php/Tests/IpReputationTest.php +1 -1
- package/src/php/Tests/ProblemManagerTest.php +1 -1
- package/src/php/Tests/QuicFingerprintTest.php +9 -9
- package/src/php/Utils/RequestUtils.php +102 -45
|
@@ -1268,13 +1268,15 @@ class RequestUtils
|
|
|
1268
1268
|
if (!isset($subnetData['uas'])) {
|
|
1269
1269
|
$subnetData['uas'] = [];
|
|
1270
1270
|
}
|
|
1271
|
+
$now = time();
|
|
1272
|
+
self::decaySubnetData($subnetData, $now);
|
|
1271
1273
|
|
|
1272
1274
|
// Utilisation de la partie stable du fingerprint matériel plutôt que l'ID de cookie volatil
|
|
1273
1275
|
$currentDeviceHash = self::getCompositeDeviceHash($context);
|
|
1274
1276
|
$stableFpId = FingerprintBuilder::cyrb53(self::extractStablePart($currentDeviceHash));
|
|
1275
1277
|
|
|
1276
1278
|
$currentDeviceContributions = $subnetData['highScoreDevices'][$stableFpId] ?? 0;
|
|
1277
|
-
if ($currentDeviceContributions <
|
|
1279
|
+
if ($currentDeviceContributions < 1 && $finalScore < 95) {
|
|
1278
1280
|
$subnetData['highScoreDevices'][$stableFpId] = $currentDeviceContributions + 1;
|
|
1279
1281
|
$subnetData['highScoreCount']++;
|
|
1280
1282
|
}
|
|
@@ -1291,8 +1293,7 @@ class RequestUtils
|
|
|
1291
1293
|
if (!empty($userAgent) && !in_array($userAgent, $subnetData['uas'], true)) {
|
|
1292
1294
|
$subnetData['uas'][] = $userAgent;
|
|
1293
1295
|
}
|
|
1294
|
-
|
|
1295
|
-
$subnetData['lastActivity'] = time();
|
|
1296
|
+
$subnetData['lastActivity'] = $now;
|
|
1296
1297
|
|
|
1297
1298
|
// Limiter la taille du tableau des deviceIds pour éviter une consommation mémoire excessive.
|
|
1298
1299
|
if (count($subnetData['deviceIds']) > 100) {
|
|
@@ -1340,19 +1341,16 @@ class RequestUtils
|
|
|
1340
1341
|
$inactivitySec = $now - ($subnetData['lastActivity'] ?? $now);
|
|
1341
1342
|
$halfLives = (int)floor($inactivitySec / 1800);
|
|
1342
1343
|
|
|
1344
|
+
if ($halfLives > 0) {
|
|
1345
|
+
self::decaySubnetData($subnetData, $now);
|
|
1346
|
+
$store->set($key, $subnetData, 86400);
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1343
1349
|
$highScoreCount = $subnetData['highScoreCount'] ?? 0;
|
|
1344
1350
|
$deviceCount = isset($subnetData['deviceIds']) ? count($subnetData['deviceIds']) : 0;
|
|
1345
1351
|
$ipCount = isset($subnetData['ips']) ? count($subnetData['ips']) : 1;
|
|
1346
1352
|
$uaCount = isset($subnetData['uas']) ? count($subnetData['uas']) : 1;
|
|
1347
1353
|
|
|
1348
|
-
if ($halfLives > 0) {
|
|
1349
|
-
$decay = pow(2, $halfLives);
|
|
1350
|
-
$highScoreCount = max(0, (int)floor($highScoreCount / $decay));
|
|
1351
|
-
$deviceCount = max(0, (int)floor($deviceCount / $decay));
|
|
1352
|
-
$ipCount = max(1, (int)floor($ipCount / $decay));
|
|
1353
|
-
$uaCount = max(1, (int)floor($uaCount / $decay));
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
1354
|
if ($deviceCount === 0) {
|
|
1357
1355
|
return ['subnetScore' => 0.0];
|
|
1358
1356
|
}
|
|
@@ -1369,6 +1367,42 @@ class RequestUtils
|
|
|
1369
1367
|
|
|
1370
1368
|
return ['subnetScore' => $finalScore];
|
|
1371
1369
|
}
|
|
1370
|
+
/**
|
|
1371
|
+
* Applies temporal decay (half-life of 30 minutes) to subnet metrics.
|
|
1372
|
+
*
|
|
1373
|
+
* @param array &$subnetData Subnet data passed by reference.
|
|
1374
|
+
* @param int $now Current timestamp.
|
|
1375
|
+
*/
|
|
1376
|
+
private static function decaySubnetData(array &$subnetData, int $now): void
|
|
1377
|
+
{
|
|
1378
|
+
$inactivitySec = $now - ($subnetData['lastActivity'] ?? $now);
|
|
1379
|
+
$halfLives = (int)floor($inactivitySec / 1800);
|
|
1380
|
+
|
|
1381
|
+
if ($halfLives > 0) {
|
|
1382
|
+
$decay = pow(2, $halfLives);
|
|
1383
|
+
$subnetData['highScoreCount'] = max(0, (int)floor(($subnetData['highScoreCount'] ?? 0) / $decay));
|
|
1384
|
+
|
|
1385
|
+
if (isset($subnetData['highScoreDevices'])) {
|
|
1386
|
+
foreach ($subnetData['highScoreDevices'] as $fpId => $val) {
|
|
1387
|
+
$decayedVal = (int)floor($val / $decay);
|
|
1388
|
+
if ($decayedVal <= 0) {
|
|
1389
|
+
unset($subnetData['highScoreDevices'][$fpId]);
|
|
1390
|
+
} else {
|
|
1391
|
+
$subnetData['highScoreDevices'][$fpId] = $decayedVal;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
foreach (['deviceIds', 'ips', 'uas'] as $field) {
|
|
1397
|
+
if (isset($subnetData[$field])) {
|
|
1398
|
+
$newLen = max(0, (int)floor(count($subnetData[$field]) / $decay));
|
|
1399
|
+
$subnetData[$field] = array_slice($subnetData[$field], 0, $newLen);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
$subnetData['lastActivity'] = $now - ($inactivitySec % 1800);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1372
1406
|
|
|
1373
1407
|
/**
|
|
1374
1408
|
* Calcule le score d'anomalie de similarité réseau (Botnet Clustering).
|
|
@@ -1820,52 +1854,75 @@ class RequestUtils
|
|
|
1820
1854
|
}
|
|
1821
1855
|
|
|
1822
1856
|
/**
|
|
1823
|
-
* Détecte les anomalies de
|
|
1857
|
+
* Détecte les anomalies de protocole (HTTP/2 et QUIC/HTTP3) par rapport au User-Agent.
|
|
1824
1858
|
* @param RequestContext $context
|
|
1825
|
-
* @return array{'
|
|
1859
|
+
* @return array{'protocolAnomalyScore': float}
|
|
1826
1860
|
*/
|
|
1827
|
-
public static function
|
|
1861
|
+
public static function getProtocolAnomalyScore(RequestContext $context): array
|
|
1828
1862
|
{
|
|
1829
|
-
$
|
|
1830
|
-
|
|
1831
|
-
return ['quicAnomalyScore' => 0.0];
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
$parts = explode(';', $quicFp);
|
|
1835
|
-
if (count($parts) < 2) {
|
|
1836
|
-
return ['quicAnomalyScore' => 0.0];
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
$params = [];
|
|
1840
|
-
foreach (explode(',', $parts[1]) as $p) {
|
|
1841
|
-
$kv = explode('=', $p, 2);
|
|
1842
|
-
if (count($kv) === 2) {
|
|
1843
|
-
$params[$kv[0]] = $kv[1];
|
|
1844
|
-
}
|
|
1845
|
-
}
|
|
1846
|
-
$priorityOrder = $parts[2] ?? '';
|
|
1863
|
+
$http2Anomaly = 0.0;
|
|
1864
|
+
$quicAnomaly = 0.0;
|
|
1847
1865
|
|
|
1848
1866
|
$ua = $context->getHeader('user-agent') ?? '';
|
|
1849
1867
|
$uaParts = self::parseUserAgent($ua);
|
|
1850
1868
|
$browser = $uaParts['browser'] ?? null;
|
|
1851
1869
|
|
|
1852
|
-
|
|
1853
|
-
|
|
1870
|
+
// HTTP/2 Anomaly logic
|
|
1871
|
+
$h2Fp = $context->getHeader('x-http2-fingerprint') ?? $context->http2Fingerprint ?? null;
|
|
1872
|
+
if ($h2Fp && is_string($h2Fp) && $browser) {
|
|
1873
|
+
$parts = explode('|', $h2Fp);
|
|
1874
|
+
if (count($parts) >= 4) {
|
|
1875
|
+
$connWindow = (int)$parts[1];
|
|
1876
|
+
$headerOrder = $parts[3];
|
|
1877
|
+
$isChromium = str_starts_with($browser, 'Chrome') || str_starts_with($browser, 'Edge');
|
|
1878
|
+
$isFirefox = str_starts_with($browser, 'Firefox');
|
|
1879
|
+
$isSafari = str_starts_with($browser, 'Safari');
|
|
1880
|
+
|
|
1881
|
+
if ($isChromium) {
|
|
1882
|
+
if ($headerOrder && $headerOrder !== 'm,a,s,p') $http2Anomaly += 60.0;
|
|
1883
|
+
if ($connWindow === 65535 || $connWindow === 65536) $http2Anomaly += 40.0;
|
|
1884
|
+
} elseif ($isFirefox) {
|
|
1885
|
+
if ($headerOrder && $headerOrder !== 'm,s,p,a') $http2Anomaly += 60.0;
|
|
1886
|
+
} elseif ($isSafari) {
|
|
1887
|
+
if ($headerOrder && $headerOrder !== 'm,s,p,a') $http2Anomaly += 60.0;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1854
1890
|
}
|
|
1855
1891
|
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
$
|
|
1860
|
-
if ($
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1892
|
+
// QUIC Anomaly logic
|
|
1893
|
+
$quicFp = $context->getHeader('x-quic-fp') ?? $context->quicFingerprint ?? null;
|
|
1894
|
+
if ($quicFp && is_string($quicFp) && $browser) {
|
|
1895
|
+
$parts = explode(';', $quicFp);
|
|
1896
|
+
if (count($parts) >= 2) {
|
|
1897
|
+
$params = [];
|
|
1898
|
+
foreach (explode(',', $parts[1]) as $p) {
|
|
1899
|
+
$kv = explode('=', $p, 2);
|
|
1900
|
+
if (count($kv) === 2) {
|
|
1901
|
+
$params[$kv[0]] = $kv[1];
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
$priorityOrder = $parts[2] ?? '';
|
|
1905
|
+
|
|
1906
|
+
if (str_starts_with($browser, 'Chrome') || str_starts_with($browser, 'Edge')) {
|
|
1907
|
+
$maxData = isset($params['1']) ? (int)$params['1'] : 0;
|
|
1908
|
+
$maxStreams = isset($params['4']) ? (int)$params['4'] : 0;
|
|
1909
|
+
if ($maxData > 0 && $maxData < 1048576) $quicAnomaly += 40.0;
|
|
1910
|
+
if ($maxStreams > 0 && $maxStreams !== 100) $quicAnomaly += 30.0;
|
|
1911
|
+
if (!empty($priorityOrder) && !str_contains($priorityOrder, 'u=')) $quicAnomaly += 30.0;
|
|
1912
|
+
} elseif (str_starts_with($browser, 'Firefox')) {
|
|
1913
|
+
$maxData = isset($params['1']) ? (int)$params['1'] : 0;
|
|
1914
|
+
if ($maxData > 0 && $maxData > 5000000) $quicAnomaly += 40.0;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1866
1917
|
}
|
|
1867
1918
|
|
|
1868
|
-
return [
|
|
1919
|
+
return [
|
|
1920
|
+
'protocolAnomalyScore' => max(
|
|
1921
|
+
0.0,
|
|
1922
|
+
min(100.0, $http2Anomaly),
|
|
1923
|
+
min(100.0, $quicAnomaly)
|
|
1924
|
+
)
|
|
1925
|
+
];
|
|
1869
1926
|
}
|
|
1870
1927
|
|
|
1871
1928
|
/**
|