@anonympins/fingerprint 0.7.4 → 0.8.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 +59 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/public/anonympins-bot-mitigation-pow.zip +0 -0
- package/src/js/dynamic-wasm.js +218 -218
- package/src/js/fingerprint.client.js +1784 -1738
- package/src/js/fingerprint.client.obfuscated.js +1 -1
- package/src/js/fingerprint.js +489 -99
- package/src/js/fingerprint.utils.js +252 -2
- package/src/js/pow.worker.js +2 -2
- package/src/js/tests/cross_parity.test.js +3 -3
- package/src/js/tests/dns-circuit-breaker.test.js +6 -6
- package/src/js/tests/dynamic-wasm.test.js +77 -77
- package/src/js/tests/fingerprint.builder.test.js +76 -78
- package/src/js/tests/fingerprint.client.init.test.js +78 -0
- package/src/js/tests/fingerprint.client.test.js +16 -17
- package/src/js/tests/fingerprint.test.js +37 -12
- package/src/js/tests/ja3AnomalyDetector.test.js +135 -136
- package/src/js/tests/library.test.js +94 -95
- package/src/js/tests/obfuscation.test.js +8 -8
- package/src/js/tests/quicFingerprint.test.js +47 -0
- package/src/js/tests/tcpFingerprint.test.js +4 -4
- package/src/js/tests/threatIntel.test.js +40 -1
- package/src/js/upow-model-task.js +155 -112
- package/src/php/Challenge/ChallengeUtils.php +392 -86
- package/src/php/Config/SecurityProfiles.php +79 -61
- package/src/php/DirectFingerprint.php +55 -8
- package/src/php/FingerprintBuilder.php +13 -13
- package/src/php/FingerprintClient.php +6 -6
- package/src/php/FingerprintEngine.php +2122 -1690
- package/src/php/Ja3AnomalyDetector.php +22 -22
- package/src/php/Optimization/FunctionRegistry.php +4 -4
- package/src/php/Optimization/Optimization.php +6 -6
- package/src/php/RequestContext.php +11 -11
- package/src/php/Store/InMemoryStore.php +96 -66
- package/src/php/Store/MongoDbStore.php +2 -2
- package/src/php/Store/RedisStore.php +1 -1
- package/src/php/Store/StoreManager.php +48 -35
- package/src/php/Tests/ChallengeUtilsTest.php +31 -0
- package/src/php/Tests/DnsCircuitBreakerTest.php +105 -105
- package/src/php/Tests/FingerprintClientTest.php +70 -70
- package/src/php/Tests/PowTest.php +37 -39
- package/src/php/Tests/QuicFingerprintTest.php +115 -53
- package/src/php/Tests/ThreatIntelTest.php +34 -0
- package/src/php/Utils/BigInt.php +202 -202
- package/src/php/Utils/BlockList.php +13 -13
- package/src/php/Utils/Logger.php +19 -1
- package/src/php/Utils/MaliciousPatterns.php +6 -6
- package/src/php/Utils/MetricsManager.php +209 -209
- package/src/php/Utils/RequestUtils.php +362 -1
- package/src/php/Utils/TLSClientHelloParser.php +385 -369
- package/src/php/WordPress/WpDbStore.php +7 -7
- package/src/php/WordPress/anonympins-bot-mitigation-pow.php +1121 -0
- package/src/php/WordPress/fingerprint-anti-bot.php +0 -559
- package/src/php/WordPress/languages/anonympins-bot-mitigation-pow-fr_FR.mo +0 -0
- package/src/php/WordPress/languages/anonympins-bot-mitigation-pow-fr_FR.po +232 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.mo +0 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.po +297 -261
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.mo +0 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.po +348 -267
- package/src/php/WordPress/package.php +80 -101
- package/src/php/WordPress/readme.txt +21 -5
- package/src/php/bin/auto-tune.php +1 -1
- package/public/fingerprint-anti-bot.zip +0 -0
|
@@ -5,8 +5,8 @@ declare(strict_types=1);
|
|
|
5
5
|
namespace Anonympins\Fingerprint\Config;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Defines predefined security profiles for the Fingerprint library.
|
|
9
|
+
* These profiles contain suspicion score weights and trigger thresholds.
|
|
10
10
|
*/
|
|
11
11
|
class SecurityProfiles
|
|
12
12
|
{
|
|
@@ -33,18 +33,21 @@ class SecurityProfiles
|
|
|
33
33
|
'crossLayerInconsistencyScore' => 0.4,
|
|
34
34
|
'timeInconsistencyScore' => 0.9,
|
|
35
35
|
'tlsSpoofingScore' => 0.8,
|
|
36
|
-
'botScore' => 1.0,
|
|
37
|
-
'cookieDroppingScore' => 0.
|
|
38
|
-
'threatIntelScore' => 0.4,
|
|
39
|
-
'clientHintsInconsistencyScore' => 0.7,
|
|
40
|
-
'clickVarianceScore' => 0.6,
|
|
41
|
-
'subnetScore' => 0.5,
|
|
42
|
-
'
|
|
36
|
+
'botScore' => 1.0,
|
|
37
|
+
'cookieDroppingScore' => 0.4,
|
|
38
|
+
'threatIntelScore' => 0.4,
|
|
39
|
+
'clientHintsInconsistencyScore' => 0.7,
|
|
40
|
+
'clickVarianceScore' => 0.6,
|
|
41
|
+
'subnetScore' => 0.5,
|
|
42
|
+
'ipReputationScore' => 0.5,
|
|
43
|
+
'botnetClusterScore' => 0.6,
|
|
43
44
|
'tcpAnomalyScore' => 0.8,
|
|
44
|
-
'protocolAnomalyScore' => 0.8,
|
|
45
|
-
'
|
|
46
|
-
'
|
|
45
|
+
'protocolAnomalyScore' => 0.8,
|
|
46
|
+
'http2AnomalyScore' => 0.8,
|
|
47
|
+
'quicAnomalyScore' => 0.8,
|
|
48
|
+
'renderingAnomalyScore' => 0.8,
|
|
47
49
|
'virtualizationScore' => 0.8,
|
|
50
|
+
'mtuAnomalyScore' => 0.9,
|
|
48
51
|
],
|
|
49
52
|
'thresholds' => ['low' => 20, 'medium' => 45, 'high' => 75, 'block' => 95],
|
|
50
53
|
'patterns' => [
|
|
@@ -63,7 +66,7 @@ class SecurityProfiles
|
|
|
63
66
|
'minDifficultyBits' => 8,
|
|
64
67
|
'maxDifficultyBits' => 22,
|
|
65
68
|
],
|
|
66
|
-
'filterWhitelist' => 85.0, //
|
|
69
|
+
'filterWhitelist' => 85.0, // Moderate inspection strategy for allowlisted IPs/paths
|
|
67
70
|
'wasm' => true,
|
|
68
71
|
],
|
|
69
72
|
|
|
@@ -88,16 +91,20 @@ class SecurityProfiles
|
|
|
88
91
|
'timeInconsistencyScore' => 1.0,
|
|
89
92
|
'tlsSpoofingScore' => 1.0,
|
|
90
93
|
'botScore' => 1.0,
|
|
91
|
-
'cookieDroppingScore' =>
|
|
92
|
-
'threatIntelScore' => 0.7,
|
|
93
|
-
'clientHintsInconsistencyScore' => 0.9,
|
|
94
|
-
'clickVarianceScore' => 0.7,
|
|
95
|
-
'subnetScore' => 0.7,
|
|
96
|
-
'
|
|
97
|
-
'
|
|
98
|
-
'
|
|
99
|
-
'
|
|
100
|
-
|
|
94
|
+
'cookieDroppingScore' => 0.6,
|
|
95
|
+
'threatIntelScore' => 0.7,
|
|
96
|
+
'clientHintsInconsistencyScore' => 0.9,
|
|
97
|
+
'clickVarianceScore' => 0.7,
|
|
98
|
+
'subnetScore' => 0.7,
|
|
99
|
+
'ipReputationScore' => 0.7,
|
|
100
|
+
'botnetClusterScore' => 0.8,
|
|
101
|
+
'tcpAnomalyScore' => 1.0,
|
|
102
|
+
'protocolAnomalyScore' => 1.0,
|
|
103
|
+
'http2AnomalyScore' => 1.0,
|
|
104
|
+
'quicAnomalyScore' => 1.0,
|
|
105
|
+
'renderingAnomalyScore' => 1.0,
|
|
106
|
+
'virtualizationScore' => 1.0,
|
|
107
|
+
'mtuAnomalyScore' => 0.9,
|
|
101
108
|
],
|
|
102
109
|
'thresholds' => ['low' => 10, 'medium' => 35, 'high' => 65, 'block' => 90],
|
|
103
110
|
'patterns' => [
|
|
@@ -118,7 +125,7 @@ class SecurityProfiles
|
|
|
118
125
|
],
|
|
119
126
|
'challengeNewDevices' => true, // Challenge all new devices
|
|
120
127
|
'wasm' => true,
|
|
121
|
-
'filterWhitelist' => true, //
|
|
128
|
+
'filterWhitelist' => true, // Any definite attack behavior immediately bypasses the allowlist
|
|
122
129
|
],
|
|
123
130
|
|
|
124
131
|
/**
|
|
@@ -141,15 +148,20 @@ class SecurityProfiles
|
|
|
141
148
|
'timeInconsistencyScore' => 0.8,
|
|
142
149
|
'tlsSpoofingScore' => 0.7,
|
|
143
150
|
'botScore' => 0.5,
|
|
144
|
-
'cookieDroppingScore' => 0.
|
|
151
|
+
'cookieDroppingScore' => 0.5, // Important for API clients that need to maintain state
|
|
145
152
|
'threatIntelScore' => 0.5, // APIs are often targeted by malicious IPs
|
|
146
153
|
'clientHintsInconsistencyScore' => 0.6, // Relevant signal for APIs
|
|
147
154
|
'clickVarianceScore' => 0.3, // Low weight as not applicable to APIs
|
|
148
|
-
'subnetScore' => 0.8, //
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
'
|
|
152
|
-
|
|
155
|
+
'subnetScore' => 0.8, // Highly important for APIs to detect botnets
|
|
156
|
+
'ipReputationScore' => 0.6,
|
|
157
|
+
'botnetClusterScore' => 0.7,
|
|
158
|
+
'tcpAnomalyScore' => 0.8,
|
|
159
|
+
'protocolAnomalyScore' => 0.8,
|
|
160
|
+
'http2AnomalyScore' => 0.8,
|
|
161
|
+
'quicAnomalyScore' => 0.8,
|
|
162
|
+
'renderingAnomalyScore' => 0.2,
|
|
163
|
+
'virtualizationScore' => 0.5,
|
|
164
|
+
'mtuAnomalyScore' => 0.9,
|
|
153
165
|
],
|
|
154
166
|
'thresholds' => ['low' => 25, 'medium' => 50, 'high' => 80, 'block' => 95],
|
|
155
167
|
'patterns' => [
|
|
@@ -170,7 +182,7 @@ class SecurityProfiles
|
|
|
170
182
|
],
|
|
171
183
|
// This would be a callable in PHP, but for now, we represent its intent.
|
|
172
184
|
'isApiRequest' => 'req.path.startsWith("/api/") || req.headers.accept?.includes("application/json")',
|
|
173
|
-
'filterWhitelist' => 75.0, //
|
|
185
|
+
'filterWhitelist' => 75.0, // Low threshold to defend against stolen legitimate API keys/tokens
|
|
174
186
|
'wasm' => true,
|
|
175
187
|
],
|
|
176
188
|
|
|
@@ -193,19 +205,22 @@ class SecurityProfiles
|
|
|
193
205
|
'honeypotScore' => 1.0, // Crucial for comment spam
|
|
194
206
|
'crossLayerInconsistencyScore' => 0.4,
|
|
195
207
|
'timeInconsistencyScore' => 0.8,
|
|
196
|
-
'tlsSpoofingScore' => 0.6,
|
|
208
|
+
'tlsSpoofingScore' => 0.6,
|
|
197
209
|
'botScore' => 0.8,
|
|
198
|
-
'cookieDroppingScore' => 0.
|
|
199
|
-
'threatIntelScore' => 0.3,
|
|
210
|
+
'cookieDroppingScore' => 0.3,
|
|
211
|
+
'threatIntelScore' => 0.3,
|
|
200
212
|
'clientHintsInconsistencyScore' => 0.5,
|
|
201
|
-
'clickVarianceScore' => 0.5,
|
|
202
|
-
'subnetScore' => 0.4,
|
|
203
|
-
'ipReputationScore' => 0.3,
|
|
204
|
-
'botnetClusterScore' => 0.5,
|
|
205
|
-
'tcpAnomalyScore' => 0.5,
|
|
206
|
-
'protocolAnomalyScore' => 0.5,
|
|
207
|
-
'
|
|
208
|
-
|
|
213
|
+
'clickVarianceScore' => 0.5,
|
|
214
|
+
'subnetScore' => 0.4,
|
|
215
|
+
'ipReputationScore' => 0.3,
|
|
216
|
+
'botnetClusterScore' => 0.5,
|
|
217
|
+
'tcpAnomalyScore' => 0.5,
|
|
218
|
+
'protocolAnomalyScore' => 0.5,
|
|
219
|
+
'http2AnomalyScore' => 0.5,
|
|
220
|
+
'quicAnomalyScore' => 0.5,
|
|
221
|
+
'renderingAnomalyScore' => 0.5,
|
|
222
|
+
'virtualizationScore' => 0.6,
|
|
223
|
+
'mtuAnomalyScore' => 0.9,
|
|
209
224
|
],
|
|
210
225
|
'thresholds' => ['low' => 25, 'medium' => 55, 'high' => 80, 'block' => 95],
|
|
211
226
|
'patterns' => [
|
|
@@ -224,7 +239,7 @@ class SecurityProfiles
|
|
|
224
239
|
'minDifficultyBits' => 8,
|
|
225
240
|
'maxDifficultyBits' => 20,
|
|
226
241
|
],
|
|
227
|
-
'filterWhitelist' => 90.0, //
|
|
242
|
+
'filterWhitelist' => 90.0, // Highly lenient, only inspects if the score is near blocking
|
|
228
243
|
'wasm' => true,
|
|
229
244
|
],
|
|
230
245
|
|
|
@@ -241,25 +256,28 @@ class SecurityProfiles
|
|
|
241
256
|
'historyScore' => 0.4,
|
|
242
257
|
'rotationScore' => 0.6,
|
|
243
258
|
'headerAnomalyScore' => 0.2,
|
|
259
|
+
'requestPatternScore' => 0.9,
|
|
244
260
|
'inconsistencyScore' => 1.0, // Crucial for preventing account takeover
|
|
245
261
|
'behaviorScore' => 0.8, // Important for checkout/login forms
|
|
246
262
|
'honeypotScore' => 1.0,
|
|
247
263
|
'crossLayerInconsistencyScore' => 0.7,
|
|
248
|
-
// NOUVEAU: Ajout des scores manquants pour une configuration complète
|
|
249
|
-
'requestPatternScore' => 0.9, // Poids unifié pour les patterns, remplace les scores scindés
|
|
250
264
|
'timeInconsistencyScore' => 0.9,
|
|
251
265
|
'tlsSpoofingScore' => 0.9,
|
|
252
266
|
'botScore' => 1.0,
|
|
253
|
-
'cookieDroppingScore' =>
|
|
267
|
+
'cookieDroppingScore' => 0.6, // Crucial for e-commerce bot detection
|
|
254
268
|
'threatIntelScore' => 0.8, // Very important for e-commerce (scalping proxies)
|
|
255
269
|
'clientHintsInconsistencyScore' => 0.9, // Very important for e-commerce
|
|
256
270
|
'clickVarianceScore' => 0.8, // Very high weight for click variance
|
|
257
|
-
'subnetScore' => 0.9, // Crucial
|
|
258
|
-
'
|
|
259
|
-
'
|
|
260
|
-
'
|
|
261
|
-
'
|
|
262
|
-
|
|
271
|
+
'subnetScore' => 0.9, // Crucial against distributed scalping attacks
|
|
272
|
+
'ipReputationScore' => 0.8,
|
|
273
|
+
'botnetClusterScore' => 0.9,
|
|
274
|
+
'tcpAnomalyScore' => 0.9,
|
|
275
|
+
'protocolAnomalyScore' => 0.9,
|
|
276
|
+
'http2AnomalyScore' => 0.9,
|
|
277
|
+
'quicAnomalyScore' => 0.9,
|
|
278
|
+
'renderingAnomalyScore' => 0.9,
|
|
279
|
+
'virtualizationScore' => 0.9,
|
|
280
|
+
'mtuAnomalyScore' => 0.9,
|
|
263
281
|
],
|
|
264
282
|
'thresholds' => ['low' => 15, 'medium' => 40, 'high' => 70, 'block' => 90],
|
|
265
283
|
'patterns' => [
|
|
@@ -282,16 +300,16 @@ class SecurityProfiles
|
|
|
282
300
|
// This would be a callable in PHP, but for now, we represent its intent.
|
|
283
301
|
'isApiRequest' => 'req.path.startsWith("/api/cart") || req.path.startsWith("/api/stock") || req.path.startsWith("/api/checkout")',
|
|
284
302
|
'wasm' => true,
|
|
285
|
-
'filterWhitelist' => true, //
|
|
303
|
+
'filterWhitelist' => true, // Zero tolerance for scraping / distributed scalping
|
|
286
304
|
],
|
|
287
305
|
];
|
|
288
306
|
|
|
289
307
|
/**
|
|
290
|
-
*
|
|
308
|
+
* Creates a security configuration based on a named profile, with optional overrides.
|
|
291
309
|
*
|
|
292
|
-
* @param string $profileName
|
|
293
|
-
* @param array<string, mixed> $overrides
|
|
294
|
-
* @return array<string, mixed>
|
|
310
|
+
* @param string $profileName The profile name to use ('balanced', 'strict', 'api', etc.).
|
|
311
|
+
* @param array<string, mixed> $overrides An array to deep-merge with the profile, allowing customization.
|
|
312
|
+
* @return array<string, mixed> The final security configuration object.
|
|
295
313
|
*/
|
|
296
314
|
public static function createSecurityProfile(string $profileName = 'balanced', array $overrides = []): array
|
|
297
315
|
{
|
|
@@ -300,11 +318,11 @@ class SecurityProfiles
|
|
|
300
318
|
}
|
|
301
319
|
|
|
302
320
|
/**
|
|
303
|
-
*
|
|
321
|
+
* Deep-merges two arrays. Properties of the `$source` array overwrite those of `$target`.
|
|
304
322
|
*
|
|
305
|
-
* @param array<string, mixed> $target
|
|
306
|
-
* @param array<string, mixed> $source
|
|
307
|
-
* @return array<string, mixed>
|
|
323
|
+
* @param array<string, mixed> $target The target array.
|
|
324
|
+
* @param array<string, mixed> $source The source array.
|
|
325
|
+
* @return array<string, mixed> The merged array.
|
|
308
326
|
*/
|
|
309
327
|
public static function deepMerge(array $target, array $source): array
|
|
310
328
|
{
|
|
@@ -25,15 +25,10 @@ class DirectFingerprint
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
29
|
-
* Analyzes the incoming request and issues challenges or block responses, exiting the script if necessary.
|
|
30
|
-
* If the request is allowed, returns the fingerprint data.
|
|
31
|
-
*
|
|
32
|
-
* @return array{score: float, vector: array}|null Fingerprint data if allowed, null otherwise.
|
|
28
|
+
* Builds request context from PHP superglobals.
|
|
33
29
|
*/
|
|
34
|
-
public function
|
|
30
|
+
public function buildRequestContext(): RequestContext
|
|
35
31
|
{
|
|
36
|
-
// 1. Build request context from PHP superglobals
|
|
37
32
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended -- Direct WAF inspection firewall before WP core logic
|
|
38
33
|
$body = $_POST ?: json_decode(file_get_contents('php://input'), true);
|
|
39
34
|
$headers = function_exists('getallheaders') ? getallheaders() : [];
|
|
@@ -44,7 +39,7 @@ class DirectFingerprint
|
|
|
44
39
|
$path = function_exists('wp_parse_url') ? (string)wp_parse_url($rawUri, PHP_URL_PATH) : (string)parse_url($rawUri, PHP_URL_PATH);
|
|
45
40
|
$serverProtocol = isset($_SERVER['SERVER_PROTOCOL']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_PROTOCOL'])) : '1.1';
|
|
46
41
|
|
|
47
|
-
|
|
42
|
+
return new RequestContext(
|
|
48
43
|
$remoteAddr,
|
|
49
44
|
!empty($path) ? $path : '/',
|
|
50
45
|
$headers,
|
|
@@ -54,10 +49,62 @@ class DirectFingerprint
|
|
|
54
49
|
$_COOKIE,
|
|
55
50
|
$serverProtocol
|
|
56
51
|
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Inspects the incoming request without terminating execution or issuing redirects/exits.
|
|
56
|
+
*
|
|
57
|
+
* @param RequestContext|null $context
|
|
58
|
+
* @return array
|
|
59
|
+
*/
|
|
60
|
+
public function inspect(?RequestContext $context = null): array
|
|
61
|
+
{
|
|
62
|
+
$context = $context ?? $this->buildRequestContext();
|
|
63
|
+
$decision = $this->engine->processRequest($context);
|
|
64
|
+
|
|
65
|
+
return [
|
|
66
|
+
'action' => $decision['action'] ?? 'next',
|
|
67
|
+
'intendedAction' => $decision['intendedAction'] ?? null,
|
|
68
|
+
'score' => (float)($decision['score'] ?? 0.0),
|
|
69
|
+
'suspicionScore' => (float)($decision['score'] ?? 0.0),
|
|
70
|
+
'vector' => $decision['vector'] ?? [],
|
|
71
|
+
'status' => $decision['status'] ?? 200,
|
|
72
|
+
'body' => $decision['body'] ?? null,
|
|
73
|
+
'context' => $context,
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Alias for inspect().
|
|
79
|
+
*
|
|
80
|
+
* @param RequestContext|null $context
|
|
81
|
+
* @return array
|
|
82
|
+
*/
|
|
83
|
+
public function evaluate(?RequestContext $context = null): array
|
|
84
|
+
{
|
|
85
|
+
return $this->inspect($context);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Protects the current entry point.
|
|
90
|
+
* Analyzes the incoming request and issues challenges or block responses, exiting the script if necessary.
|
|
91
|
+
* If the request is allowed, returns the fingerprint data.
|
|
92
|
+
*
|
|
93
|
+
* @return array{score: float, vector: array}|null Fingerprint data if allowed, null otherwise.
|
|
94
|
+
*/
|
|
95
|
+
public function protect(): ?array
|
|
96
|
+
{
|
|
97
|
+
// 1. Build request context from PHP superglobals
|
|
98
|
+
$context = $this->buildRequestContext();
|
|
57
99
|
|
|
58
100
|
// 2. Process request with engine
|
|
59
101
|
$decision = $this->engine->processRequest($context);
|
|
60
102
|
|
|
103
|
+
// 3. Callback hook before acting on decision (allows logging, telemetry, SSE recording)
|
|
104
|
+
if (isset($this->securityConfig['onDecision']) && is_callable($this->securityConfig['onDecision'])) {
|
|
105
|
+
call_user_func($this->securityConfig['onDecision'], $decision, $context);
|
|
106
|
+
}
|
|
107
|
+
|
|
61
108
|
// 3. Act on decision
|
|
62
109
|
if (isset($context->newCookieForResponse)) {
|
|
63
110
|
$cookie = $context->newCookieForResponse;
|
|
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
|
|
5
5
|
namespace Anonympins\Fingerprint;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Builds a composite fingerprint (Multi-Hash).
|
|
9
9
|
* Output format: "grp1:hash1|grp2:hash2|grp3:hash3"
|
|
10
10
|
*/
|
|
11
11
|
class FingerprintBuilder
|
|
@@ -17,7 +17,7 @@ class FingerprintBuilder
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Adds a component to the fingerprint.
|
|
20
|
-
*
|
|
20
|
+
*
|
|
21
21
|
* @param string $group Group name (e.g. 'hw', 'screen', 'geo').
|
|
22
22
|
* @param string|int|bool|null $value Raw value to hash.
|
|
23
23
|
* @return self
|
|
@@ -27,14 +27,14 @@ class FingerprintBuilder
|
|
|
27
27
|
if ($value === null || $value === '') {
|
|
28
28
|
return $this;
|
|
29
29
|
}
|
|
30
|
-
// Hash the value individually
|
|
30
|
+
// Hash the value individually to anonymize and normalize its length.
|
|
31
31
|
$this->components[$group] = self::cyrb53((string)$value);
|
|
32
32
|
return $this;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Adds a raw component without hashing it.
|
|
37
|
-
* Useful for metrics that need to be read as-is on the server.
|
|
37
|
+
* Useful for metrics that need to be read as-is on the server side.
|
|
38
38
|
*
|
|
39
39
|
* @param string $group Group name.
|
|
40
40
|
* @param string|int|null $value Raw value.
|
|
@@ -51,13 +51,13 @@ class FingerprintBuilder
|
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Generates the final fingerprint string.
|
|
54
|
-
* Components are sorted by key to
|
|
54
|
+
* Components are sorted by key to ensure deterministic ordering.
|
|
55
55
|
*
|
|
56
56
|
* @return string
|
|
57
57
|
*/
|
|
58
58
|
public function __toString(): string
|
|
59
59
|
{
|
|
60
|
-
// Sort array by key
|
|
60
|
+
// Sort array by key.
|
|
61
61
|
ksort($this->components);
|
|
62
62
|
|
|
63
63
|
$parts = [];
|
|
@@ -70,7 +70,7 @@ class FingerprintBuilder
|
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* Compares two fingerprints and returns a similarity score (0 to 1).
|
|
73
|
-
* Uses weights to emphasize strong invariants (Canvas, GPU, JA3).
|
|
73
|
+
* Uses weights to emphasize strong invariants (e.g., Canvas, GPU, JA3).
|
|
74
74
|
*
|
|
75
75
|
* @param string|null $fpString1 Fingerprint A.
|
|
76
76
|
* @param string|null $fpString2 Fingerprint B.
|
|
@@ -137,7 +137,7 @@ class FingerprintBuilder
|
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
139
|
* cyrb53 hashing algorithm (fast and low collision rate).
|
|
140
|
-
*
|
|
140
|
+
* This is a direct port of the JavaScript version.
|
|
141
141
|
*
|
|
142
142
|
* @param string $str String to hash.
|
|
143
143
|
* @param int $seed Optional seed.
|
|
@@ -157,8 +157,8 @@ class FingerprintBuilder
|
|
|
157
157
|
$h1 = self::imul($h1 ^ ($h1 >> 16), 2246822507) ^ self::imul($h2 ^ ($h2 >> 13), 3266489909);
|
|
158
158
|
$h2 = self::imul($h2 ^ ($h2 >> 16), 2246822507) ^ self::imul($h1 ^ ($h1 >> 13), 3266489909);
|
|
159
159
|
|
|
160
|
-
// On 64-bit platforms, PHP handles 64-bit signed
|
|
161
|
-
// Use native shifts instead of bcmath for
|
|
160
|
+
// On 64-bit platforms, PHP handles 64-bit signed integers natively.
|
|
161
|
+
// Use native shifts instead of bcmath for improved performance.
|
|
162
162
|
if (PHP_INT_SIZE === 8) {
|
|
163
163
|
$h1_u = $h1 & 0xffffffff;
|
|
164
164
|
$h2_u = $h2 & 0xffffffff;
|
|
@@ -166,7 +166,7 @@ class FingerprintBuilder
|
|
|
166
166
|
return (string)$val_h2;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
// Fallback to bcmath on 32-bit platforms
|
|
169
|
+
// Fallback to bcmath on 32-bit platforms.
|
|
170
170
|
$val_h2 = bcadd(bcmul((string)(2097151 & $h2), '4294967296'), (string)($h1 >= 0 ? $h1 : $h1 + 4294967296));
|
|
171
171
|
return $val_h2;
|
|
172
172
|
}
|
|
@@ -180,8 +180,8 @@ class FingerprintBuilder
|
|
|
180
180
|
*/
|
|
181
181
|
private static function imul(int $a, int $b): int
|
|
182
182
|
{
|
|
183
|
-
//
|
|
184
|
-
// This
|
|
183
|
+
// Emulates JavaScript's Math.imul for signed 32-bit integer multiplication.
|
|
184
|
+
// This implementation correctly handles overflows on 64-bit systems.
|
|
185
185
|
$ah = ($a >> 16) & 0xffff;
|
|
186
186
|
$al = $a & 0xffff;
|
|
187
187
|
$bh = ($b >> 16) & 0xffff;
|
|
@@ -6,8 +6,8 @@ namespace Anonympins\Fingerprint;
|
|
|
6
6
|
use Anonympins\Fingerprint\Config\SecurityProfiles;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* PHP wrapper for the client-side fingerprinting library.
|
|
10
|
+
*
|
|
11
11
|
* Handles script injection and generation of polymorphic honeypot fields
|
|
12
12
|
* inside HTML forms.
|
|
13
13
|
*/
|
|
@@ -64,7 +64,7 @@ class FingerprintClient
|
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* Generates a hidden honeypot form field.
|
|
67
|
-
* Traps automated bots while remaining invisible to human users.
|
|
67
|
+
* Traps automated bots while remaining invisible to human users and screen readers.
|
|
68
68
|
*
|
|
69
69
|
* @param string $fieldName Field name (must match client honeypot registration).
|
|
70
70
|
* @return string Generated HTML markup.
|
|
@@ -76,7 +76,7 @@ class FingerprintClient
|
|
|
76
76
|
$this->clientConfig['honeypots'][] = $fieldName;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
// Polymorphic CSS styling to robustly obscure
|
|
79
|
+
// Polymorphic CSS styling to robustly obscure honeypot fields
|
|
80
80
|
$styleOptions = [
|
|
81
81
|
'position:absolute; left:-9999px; top:-9999px; transform:scale(0); opacity:0; pointer-events:none;',
|
|
82
82
|
'position:fixed; left:-8888px; top:-8888px; width:0; height:0; overflow:hidden; opacity:0; pointer-events:none;',
|
|
@@ -112,7 +112,7 @@ class FingerprintClient
|
|
|
112
112
|
$configJson = json_encode($this->clientConfig);
|
|
113
113
|
$nonceAttr = $this->nonce ? ' nonce="' . $this->nonce . '"' : '';
|
|
114
114
|
|
|
115
|
-
// Inline initialization script embedded in HTML
|
|
115
|
+
// Inline initialization script to be embedded in HTML
|
|
116
116
|
$initScript = "document.addEventListener('DOMContentLoaded', function() {\n"
|
|
117
117
|
. " const config = " . $configJson . ";\n"
|
|
118
118
|
. " if (window.ClientLibrary) {\n"
|
|
@@ -129,7 +129,7 @@ class FingerprintClient
|
|
|
129
129
|
. " }\n"
|
|
130
130
|
. "});";
|
|
131
131
|
|
|
132
|
-
// Combine library loader script and inline initialization
|
|
132
|
+
// Combine the main library loader script and the inline initialization script
|
|
133
133
|
// phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Polymorphic dynamic client script tag generation
|
|
134
134
|
return '<script src="' . htmlspecialchars($this->clientScriptPath) . '"' . $nonceAttr . '></script>'
|
|
135
135
|
. '<script' . $nonceAttr . '>' . $initScript . '</script>';
|