@anonympins/fingerprint 0.6.6 → 0.7.0
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 +32 -0
- package/README.md +11 -2
- package/package.json +1 -1
- package/public/fp.js +1 -1
- package/public/fp.wasm +0 -0
- package/src/js/build-client.js +1 -1
- package/src/js/dynamic-wasm.js +7 -7
- package/src/js/fingerprint.client.js +1463 -1447
- package/src/js/fingerprint.js +386 -94
- package/src/js/library.js +15 -8
- package/src/js/pow.solver.inline.js +56 -10
- package/src/js/pow.solver.js +56 -10
- package/src/js/pow.worker.js +35 -13
- package/src/js/problem-manager.js +10 -3
- package/src/js/tests/fingerprint.engine.test.js +25 -0
- package/src/js/tests/fingerprint.test.js +69 -35
- package/src/php/Challenge/ChallengeUtils.php +149 -23
- package/src/php/Config/SecurityProfiles.php +1 -0
- package/src/php/FingerprintClient.php +148 -148
- package/src/php/FingerprintEngine.php +39 -84
- package/src/php/Ja3AnomalyDetector.php +257 -227
- package/src/php/Optimization/OptimizationOperators.php +2 -2
- package/src/php/ProblemManager.php +83 -0
- package/src/php/Tests/FingerprintEngineTest.php +2 -33
- package/src/php/Utils/RequestUtils.php +114 -11
- package/src/php/Utils/TLSClientHelloParser.php +158 -1
- package/src/js/fingerprint.client.obfuscated.js +0 -1
|
@@ -81,83 +81,31 @@
|
|
|
81
81
|
return null;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
private static function
|
|
84
|
+
private static function resolveDnsNative(string $query, string $type): ?array
|
|
85
85
|
{
|
|
86
|
-
$
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
$
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
$qType = ($type === 'PTR') ? 12 : (($type === 'AAAA') ? 28 : 1);
|
|
96
|
-
$parts = explode('.', $query);
|
|
97
|
-
$qName = '';
|
|
98
|
-
foreach ($parts as $part) {
|
|
99
|
-
$qName .= chr(strlen($part)) . $part;
|
|
86
|
+
$typeMap = [
|
|
87
|
+
'PTR' => DNS_PTR,
|
|
88
|
+
'A' => DNS_A,
|
|
89
|
+
'AAAA' => DNS_AAAA
|
|
90
|
+
];
|
|
91
|
+
$dnsType = $typeMap[$type] ?? null;
|
|
92
|
+
if ($dnsType === null) {
|
|
93
|
+
return null;
|
|
100
94
|
}
|
|
101
|
-
|
|
102
|
-
$
|
|
103
|
-
|
|
104
|
-
if (!@fwrite($fp, $header . $question)) {
|
|
105
|
-
fclose($fp);
|
|
95
|
+
|
|
96
|
+
$records = @dns_get_record($query, $dnsType);
|
|
97
|
+
if ($records === false) {
|
|
106
98
|
return null;
|
|
107
99
|
}
|
|
108
|
-
|
|
109
|
-
$response = @fread($fp, 512);
|
|
110
|
-
fclose($fp);
|
|
111
|
-
if (!$response || strlen($response) < 12) return null;
|
|
112
|
-
|
|
113
|
-
$resHeader = unpack('n6', substr($response, 0, 12));
|
|
114
|
-
if ($resHeader[1] !== $id) return null;
|
|
115
|
-
|
|
116
|
-
$answersCount = $resHeader[4];
|
|
117
|
-
if ($answersCount <= 0) return [];
|
|
118
|
-
|
|
119
|
-
$offset = 12 + strlen($question);
|
|
100
|
+
|
|
120
101
|
$results = [];
|
|
121
|
-
|
|
122
|
-
if ($
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
$offset++;
|
|
130
|
-
}
|
|
131
|
-
if ($offset + 10 > strlen($response)) break;
|
|
132
|
-
$typeAndClass = unpack('n2type_class/Nttl/nlen', substr($response, $offset, 10));
|
|
133
|
-
$rType = $typeAndClass['type_class1'];
|
|
134
|
-
$rLen = $typeAndClass['len'];
|
|
135
|
-
$offset += 10;
|
|
136
|
-
if ($offset + $rLen > strlen($response)) break;
|
|
137
|
-
$rData = substr($response, $offset, $rLen);
|
|
138
|
-
$offset += $rLen;
|
|
139
|
-
|
|
140
|
-
if ($rType === 12) {
|
|
141
|
-
$ptrName = '';
|
|
142
|
-
$p = 0;
|
|
143
|
-
while ($p < strlen($rData)) {
|
|
144
|
-
$l = ord($rData[$p]);
|
|
145
|
-
if ($l === 0) break;
|
|
146
|
-
if (($l & 0xc0) === 0xc0) {
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
$ptrName .= substr($rData, $p + 1, $l) . '.';
|
|
150
|
-
$p += 1 + $l;
|
|
151
|
-
}
|
|
152
|
-
$results[] = rtrim($ptrName, '.');
|
|
153
|
-
} elseif ($rType === 1) {
|
|
154
|
-
if ($rLen === 4) {
|
|
155
|
-
$results[] = long2ip(unpack('N', $rData)[1]);
|
|
156
|
-
}
|
|
157
|
-
} elseif ($rType === 28) {
|
|
158
|
-
if ($rLen === 16) {
|
|
159
|
-
$results[] = inet_ntop($rData);
|
|
160
|
-
}
|
|
102
|
+
foreach ($records as $record) {
|
|
103
|
+
if ($type === 'PTR' && isset($record['target'])) {
|
|
104
|
+
$results[] = $record['target'];
|
|
105
|
+
} elseif ($type === 'A' && isset($record['ip'])) {
|
|
106
|
+
$results[] = $record['ip'];
|
|
107
|
+
} elseif ($type === 'AAAA' && isset($record['ipv6'])) {
|
|
108
|
+
$results[] = $record['ipv6'];
|
|
161
109
|
}
|
|
162
110
|
}
|
|
163
111
|
return $results;
|
|
@@ -690,10 +638,8 @@
|
|
|
690
638
|
// Score d'incohérence du fingerprint (déplacé ici pour être avec les autres)
|
|
691
639
|
$currentDeviceHash = RequestUtils::getCompositeDeviceHash($context);
|
|
692
640
|
$consistencyScore = FingerprintBuilder::compare($deviceData['initialDeviceHash'] ?? '', $currentDeviceHash);
|
|
693
|
-
$
|
|
694
|
-
|
|
695
|
-
$inconsistencyScore = 100.0;
|
|
696
|
-
}
|
|
641
|
+
$similarityThreshold = (float)($this->securityConfig['similarityThreshold'] ?? 0.72);
|
|
642
|
+
$inconsistencyScore = RequestUtils::calculateAnalogInconsistencyScore($consistencyScore, $similarityThreshold);
|
|
697
643
|
|
|
698
644
|
$behavioral = RequestUtils::getBehavioralIndicators($context, $deviceData);
|
|
699
645
|
|
|
@@ -703,6 +649,7 @@
|
|
|
703
649
|
// Score de spoofing TLS
|
|
704
650
|
$tlsSpoofing = RequestUtils::getTlsSpoofingScore($context);
|
|
705
651
|
$tlsSpoofingScore = (float)($tlsSpoofing['tlsSpoofingScore'] ?? 0.0);
|
|
652
|
+
$virtualizationScore = RequestUtils::getVirtualizationAnomalyScore($context);
|
|
706
653
|
|
|
707
654
|
// Advanced JA4 TLS Inconsistency checks
|
|
708
655
|
$ja4 = $context->getHeader('x-ja4-hash');
|
|
@@ -830,6 +777,7 @@
|
|
|
830
777
|
'tcpAnomalyScore' => $tcpAnomaly['tcpAnomalyScore'],
|
|
831
778
|
'protocolAnomalyScore' => $protocolAnomaly['protocolAnomalyScore'],
|
|
832
779
|
'renderingAnomalyScore' => $renderingAnomaly['renderingAnomalyScore'],
|
|
780
|
+
'virtualizationScore' => $virtualizationScore
|
|
833
781
|
]);
|
|
834
782
|
|
|
835
783
|
// Sauvegarder l'état mis à jour de l'appareil dans le store
|
|
@@ -1233,7 +1181,8 @@
|
|
|
1233
1181
|
|
|
1234
1182
|
// 5. Prendre une décision basée sur le score - Vérifier le blocage d'abord.
|
|
1235
1183
|
$blockThreshold = $thresholds['block'] ?? 95;
|
|
1236
|
-
|
|
1184
|
+
$isBlocked = $finalScore >= $blockThreshold;
|
|
1185
|
+
if ($isBlocked) {
|
|
1237
1186
|
if ($this->logger) {
|
|
1238
1187
|
MetricsManager::incrementCounter('requests_total', ['status' => 'blocked']);
|
|
1239
1188
|
$this->logger->log('info', 'request_blocked', ['deviceId' => $deviceId, 'score' => $finalScore, 'vector' => $suspicionVector]);
|
|
@@ -1295,8 +1244,14 @@
|
|
|
1295
1244
|
return $decision;
|
|
1296
1245
|
}
|
|
1297
1246
|
|
|
1298
|
-
$
|
|
1299
|
-
$
|
|
1247
|
+
$mediumThreshold = $thresholds['medium'] ?? 45;
|
|
1248
|
+
$maxIndicatorsCount = 0;
|
|
1249
|
+
foreach ($suspicionVector as $val) {
|
|
1250
|
+
if (is_numeric($val) && (float)$val >= 100.0) {
|
|
1251
|
+
$maxIndicatorsCount++;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
$mustReChallenge = (($suspicionVector['honeypotScore'] ?? 0.0) >= $mediumThreshold) || ($maxIndicatorsCount >= 1);
|
|
1300
1255
|
|
|
1301
1256
|
$lowThreshold = $thresholds['low'] ?? 20;
|
|
1302
1257
|
if (($finalScore >= $lowThreshold && !$hasValidTicket) || $mustReChallenge) {
|
|
@@ -1665,12 +1620,12 @@
|
|
|
1665
1620
|
|
|
1666
1621
|
try {
|
|
1667
1622
|
// 1. Reverse DNS lookup with strict 500ms timeout using our custom UDP DNS Client
|
|
1668
|
-
$revName = self::getReverseDnsName($context->
|
|
1623
|
+
$revName = self::getReverseDnsName($context->clientIp);
|
|
1669
1624
|
if (!$revName) {
|
|
1670
1625
|
$store->set($cacheKey, 'failed', 300); // 5 min negative caching
|
|
1671
1626
|
return false;
|
|
1672
1627
|
}
|
|
1673
|
-
$hostnames = self::
|
|
1628
|
+
$hostnames = self::resolveDnsNative($revName, 'PTR');
|
|
1674
1629
|
if ($hostnames === null || empty($hostnames)) {
|
|
1675
1630
|
self::recordDnsFailure();
|
|
1676
1631
|
$store->set($cacheKey, 'failed', 300); // 5 min negative caching
|
|
@@ -1692,7 +1647,7 @@
|
|
|
1692
1647
|
|
|
1693
1648
|
// 2. Forward DNS lookup with strict 500ms timeout
|
|
1694
1649
|
$ips = [];
|
|
1695
|
-
$resolvedA = self::
|
|
1650
|
+
$resolvedA = self::resolveDnsNative($validHostname, 'A');
|
|
1696
1651
|
if ($resolvedA === null) {
|
|
1697
1652
|
self::recordDnsFailure();
|
|
1698
1653
|
$store->set($cacheKey, 'failed', 300); // 5 min negative caching
|
|
@@ -1700,7 +1655,7 @@
|
|
|
1700
1655
|
}
|
|
1701
1656
|
$ips = array_merge($ips, $resolvedA);
|
|
1702
1657
|
|
|
1703
|
-
$resolvedAaaa = self::
|
|
1658
|
+
$resolvedAaaa = self::resolveDnsNative($validHostname, 'AAAA');
|
|
1704
1659
|
if ($resolvedAaaa === null) {
|
|
1705
1660
|
self::recordDnsFailure();
|
|
1706
1661
|
$store->set($cacheKey, 'failed', 300); // 5 min negative caching
|
|
@@ -1708,7 +1663,7 @@
|
|
|
1708
1663
|
}
|
|
1709
1664
|
$ips = array_merge($ips, $resolvedAaaa);
|
|
1710
1665
|
|
|
1711
|
-
if (in_array($context->
|
|
1666
|
+
if (in_array($context->clientIp, $ips, true)) {
|
|
1712
1667
|
self::recordDnsSuccess();
|
|
1713
1668
|
$store->set($cacheKey, 'verified', 86400);
|
|
1714
1669
|
return true;
|