@anonympins/fingerprint 0.7.2 → 0.7.3

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +22 -9
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/public/fingerprint-anti-bot.zip +0 -0
  5. package/src/js/fingerprint.js +68 -23
  6. package/src/js/fingerprint.utils.js +32 -5
  7. package/src/js/tests/fingerprint.test.js +1 -1
  8. package/src/js/tests/threatIntel.test.js +76 -0
  9. package/src/php/AutoTuner.php +36 -18
  10. package/src/php/Challenge/ChallengeUtils.php +106 -224
  11. package/src/php/DirectFingerprint.php +16 -4
  12. package/src/php/FingerprintClient.php +17 -19
  13. package/src/php/FingerprintEngine.php +77 -39
  14. package/src/php/Ja3AnomalyDetector.php +20 -12
  15. package/src/php/Optimization/Optimization.php +5 -1
  16. package/src/php/Optimization/OptimizationOperators.php +5 -1
  17. package/src/php/Optimization/ProblemInitializers.php +16 -4
  18. package/src/php/ProblemManager.php +20 -14
  19. package/src/php/Tests/FingerprintEngineTest.php +6 -1
  20. package/src/php/Tests/ThreatIntelTest.php +64 -0
  21. package/src/php/Utils/Env.php +51 -49
  22. package/src/php/Utils/MaliciousPatterns.php +74 -74
  23. package/src/php/Utils/RequestUtils.php +22 -5
  24. package/src/php/WordPress/WpDbStore.php +4 -0
  25. package/src/php/WordPress/{fingerprint-wordpress.php → fingerprint-anti-bot.php} +131 -126
  26. package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.mo +0 -0
  27. package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.po +1 -1
  28. package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.mo +0 -0
  29. package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.po +1 -1
  30. package/src/php/WordPress/package.php +6 -3
  31. package/src/php/WordPress/readme.txt +36 -0
  32. package/public/fingerprint-wordpress.zip +0 -0
  33. package/src/js/fingerprint.client.obfuscated.js +0 -1
@@ -1,75 +1,75 @@
1
- <?php
2
-
3
- declare(strict_types=1);
4
-
5
- namespace Anonympins\Fingerprint\Utils;
6
-
7
- /**
8
- * Fournit des fonctions pour détecter les patterns d'injection malveillants.
9
- */
10
- class MaliciousPatterns
11
- {
12
- /**
13
- * @var array<string, string> Map des patterns malveillants regroupés par type.
14
- */
15
- private const INJECTION_PATTERNS = [
16
- // SQL/NoSQL injections, including time-based attacks
17
- 'sql' => '/(\$ne|\' *OR *\'1\'=\'1|[\'";]\s*--|; ?(DROP|TRUNCATE|DELETE)|UNION SELECT|(?:SLEEP|BENCHMARK)\s*\(|WAITFOR DELAY)/i',
18
- // Log4Shell (JNDI injection)
19
- 'log4shell' => '/\$\{jndi:(ldap|rmi|dns):/i',
20
- // Server-Side Template Injection (SSTI) for engines like Jinja2, Twig, etc.
21
- 'ssti' => '/\{\{.*\}\}|\{%.*%\}/',
22
- // XML External Entity (XXE) injection
23
- 'xxe' => '/<!ENTITY\s+.*SYSTEM/i',
24
- // Path Traversal
25
- 'traversal' => '/(\.\.\/|\.\.)/',
26
- // Remote Command Execution (RCE)
27
- // The original regex had an issue with `|cmd` being interpreted as a modifier in some PCRE versions.
28
- // Using a non-capturing group (?:...) makes it more robust and fixes the compilation error.
29
- 'rce' => '/`.*`|(?:^|[\n;&|]\s*)(?:ping|ls|whoami|cat|rm|ncat|nc|bash|sh|powershell|cmd)\b/i',
30
- // Server-Side Request Forgery (SSRF)
31
- 'ssrf' => '/(?:https?:\/\/)?(?:127\.\d+\.\d+\.\d+|169\.254\.169\.254|10\.\d+\.\d+\.\d+|172\.(?:1[6-9]|2\d|3[01])\.\d+\.\d+|192\.168\.\d+\.\d+|localhost|0\.0\.0\.0|\[[0:]+1\])\b/i',
32
- // Carriage Return Line Feed (CRLF) Injection
33
- 'crlf' => '/[\r\n]|%0[ad]/i',
34
- // Cross-Site Scripting (XSS)
35
- 'xss' => '/(<script|javascript:|on\w+\s*=|alert\s*\(|confirm\s*\(|prompt\s*\(|<img\s+src[^>]+onerror|<iframe)/i',
36
- // Open Redirect
37
- 'openRedirect' => '/^(https?:)?\/\/(?![^\/]*?(localhost|127\.0\.0\.1))[^\s\/]+/i',
38
- // Local/Remote File Inclusion (LFI/RFI)
39
- 'lfi' => '/(?:etc\/passwd|win\.ini|boot\.ini|php:\/\/filter|data:\/\/|zip:\/\/)/i',
40
- // Shellshock (CVE-2014-6271)
41
- 'shellshock' => '/\(\)\s*\{\s*:\s*;\s*\}\s*/i',
42
- // NoSQL Injection (MongoDB query operators)
43
- 'nosql' => '/\$(?:eq|ne|gt|gte|lt|lte|in|nin|and|or|nor|not|expr|jsonSchema|mod|regex|text|where|elemMatch)/i',
44
- ];
45
-
46
- /**
47
- * Vérifie si une chaîne de caractères contient des patterns d'injection connus.
48
- * @param string $str La chaîne à vérifier.
49
- * @param array<string> $typesToDetect Les types d'injections à détecter (par défaut, tous).
50
- * @return bool True si un pattern malveillant est détecté, false sinon.
51
- */
52
- public static function isMalicious(string $str, array $typesToDetect = []): bool
53
- {
54
- if (empty($typesToDetect)) {
55
- $typesToDetect = array_filter(array_keys(self::INJECTION_PATTERNS), function ($key) {
56
- return $key !== 'openRedirect';
57
- });
58
- }
59
-
60
- foreach ($typesToDetect as $type) {
61
- if (isset(self::INJECTION_PATTERNS[$type])) {
62
- try {
63
- if (preg_match(self::INJECTION_PATTERNS[$type], $str)) {
64
- return true;
65
- }
66
- }catch (\Exception $e){
67
- error_log($type);
68
- error_log($e->getMessage());
69
- }
70
- }
71
- }
72
-
73
- return false;
74
- }
1
+ <?php
2
+
3
+ declare(strict_types=1);
4
+
5
+ namespace Anonympins\Fingerprint\Utils;
6
+
7
+ /**
8
+ * Fournit des fonctions pour détecter les patterns d'injection malveillants.
9
+ */
10
+ class MaliciousPatterns
11
+ {
12
+ /**
13
+ * @var array<string, string> Map des patterns malveillants regroupés par type.
14
+ */
15
+ private const INJECTION_PATTERNS = [
16
+ // SQL/NoSQL injections, including time-based attacks
17
+ 'sql' => '/(\$ne|\' *OR *\'1\'=\'1|[\'";]\s*--|; ?(DROP|TRUNCATE|DELETE)|UNION SELECT|(?:SLEEP|BENCHMARK)\s*\(|WAITFOR DELAY)/i',
18
+ // Log4Shell (JNDI injection)
19
+ 'log4shell' => '/\$\{jndi:(ldap|rmi|dns):/i',
20
+ // Server-Side Template Injection (SSTI) for engines like Jinja2, Twig, etc.
21
+ 'ssti' => '/\{\{.*\}\}|\{%.*%\}/',
22
+ // XML External Entity (XXE) injection
23
+ 'xxe' => '/<!ENTITY\s+.*SYSTEM/i',
24
+ // Path Traversal
25
+ 'traversal' => '/(\.\.\/|\.\.)/',
26
+ // Remote Command Execution (RCE)
27
+ // The original regex had an issue with `|cmd` being interpreted as a modifier in some PCRE versions.
28
+ // Using a non-capturing group (?:...) makes it more robust and fixes the compilation error.
29
+ 'rce' => '/`.*`|(?:^|[\n;&|]\s*)(?:ping|ls|whoami|cat|rm|ncat|nc|bash|sh|powershell|cmd)\b/i',
30
+ // Server-Side Request Forgery (SSRF)
31
+ 'ssrf' => '/(?:https?:\/\/)?(?:127\.\d+\.\d+\.\d+|169\.254\.169\.254|10\.\d+\.\d+\.\d+|172\.(?:1[6-9]|2\d|3[01])\.\d+\.\d+|192\.168\.\d+\.\d+|localhost|0\.0\.0\.0|\[[0:]+1\])\b/i',
32
+ // Carriage Return Line Feed (CRLF) Injection
33
+ 'crlf' => '/[\r\n]|%0[ad]/i',
34
+ // Cross-Site Scripting (XSS)
35
+ 'xss' => '/(<script|javascript:|on\w+\s*=|alert\s*\(|confirm\s*\(|prompt\s*\(|<img\s+src[^>]+onerror|<iframe)/i',
36
+ // Open Redirect
37
+ 'openRedirect' => '/^(https?:)?\/\/(?![^\/]*?(localhost|127\.0\.0\.1))[^\s\/]+/i',
38
+ // Local/Remote File Inclusion (LFI/RFI)
39
+ 'lfi' => '/(?:etc\/passwd|win\.ini|boot\.ini|php:\/\/filter|data:\/\/|zip:\/\/)/i',
40
+ // Shellshock (CVE-2014-6271)
41
+ 'shellshock' => '/\(\)\s*\{\s*:\s*;\s*\}\s*/i',
42
+ // NoSQL Injection (MongoDB query operators)
43
+ 'nosql' => '/\$(?:eq|ne|gt|gte|lt|lte|in|nin|and|or|nor|not|expr|jsonSchema|mod|regex|text|where|elemMatch)/i',
44
+ ];
45
+
46
+ /**
47
+ * Vérifie si une chaîne de caractères contient des patterns d'injection connus.
48
+ * @param string $str La chaîne à vérifier.
49
+ * @param array<string> $typesToDetect Les types d'injections à détecter (par défaut, tous).
50
+ * @return bool True si un pattern malveillant est détecté, false sinon.
51
+ */
52
+ public static function isMalicious(string $str, array $typesToDetect = []): bool
53
+ {
54
+ if (empty($typesToDetect)) {
55
+ $typesToDetect = array_filter(array_keys(self::INJECTION_PATTERNS), function ($key) {
56
+ return $key !== 'openRedirect';
57
+ });
58
+ }
59
+
60
+ foreach ($typesToDetect as $type) {
61
+ if (isset(self::INJECTION_PATTERNS[$type])) {
62
+ try {
63
+ if (preg_match(self::INJECTION_PATTERNS[$type], $str)) {
64
+ return true;
65
+ }
66
+ } catch (\Exception $e) {
67
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- WAF regex validation diagnostic
68
+ error_log("Pattern inspection failed for {$type}: " . $e->getMessage());
69
+ }
70
+ }
71
+ }
72
+
73
+ return false;
74
+ }
75
75
  }
@@ -1038,19 +1038,34 @@ class RequestUtils
1038
1038
  public static function getThreatIntelScore(RequestContext $context, array $threatIntelConfig): array
1039
1039
  {
1040
1040
  $score = 0.0;
1041
+ $signals = [];
1042
+
1041
1043
  $zkpY = $context->zkpY;
1042
1044
  if (!empty($zkpY)) {
1043
1045
  $store = StoreManager::getStore();
1044
1046
  $isBanned = $store->has("banned-zkp-y:{$zkpY}");
1045
1047
  if ($isBanned) {
1046
1048
  $score = 100.0;
1049
+ $signals[] = [
1050
+ 'ruleId' => 'FEDERATED_ZKP_BANNED',
1051
+ 'confidence' => 1.0,
1052
+ 'score' => 100.0,
1053
+ 'rationale' => 'Cryptographic identity matched federated banned list consensus'
1054
+ ];
1047
1055
  }
1048
1056
  }
1049
1057
 
1050
- $rttProxyScore = \Anonympins\Fingerprint\Ja3AnomalyDetector::getRttProxyScore($context);
1051
- $score = max($score, (float)$rttProxyScore);
1058
+ $rttProxyScore = (float)\Anonympins\Fingerprint\Ja3AnomalyDetector::getRttProxyScore($context);
1059
+ if ($rttProxyScore > 0.0) {
1060
+ $score = max($score, $rttProxyScore);
1061
+ $signals[] = [
1062
+ 'ruleId' => 'RESIDENTIAL_PROXY_RTT_DISCREPANCY',
1063
+ 'score' => $rttProxyScore,
1064
+ 'rationale' => 'Physical discrepancy between TCP edge RTT and application transit latency'
1065
+ ];
1066
+ }
1052
1067
 
1053
- return ['threatIntelScore' => $score];
1068
+ return ['threatIntelScore' => $score, 'threatIntelSignals' => $signals];
1054
1069
  }
1055
1070
 
1056
1071
  /**
@@ -1145,7 +1160,8 @@ class RequestUtils
1145
1160
  */
1146
1161
  public static function cleanUrlFromPowParams(string $originalPath, array $incomingQuery): string
1147
1162
  {
1148
- $urlParts = parse_url($originalPath);
1163
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- Uses wp_parse_url when running inside WordPress
1164
+ $urlParts = function_exists('wp_parse_url') ? wp_parse_url($originalPath) : parse_url($originalPath);
1149
1165
  $path = $urlParts['path'] ?? '/';
1150
1166
  $finalQuery = $incomingQuery;
1151
1167
 
@@ -1326,7 +1342,8 @@ class RequestUtils
1326
1342
 
1327
1343
  // Utilisation de la partie stable du fingerprint matériel plutôt que l'ID de cookie volatil
1328
1344
  $currentDeviceHash = self::getCompositeDeviceHash($context);
1329
- $stableFpId = FingerprintBuilder::cyrb53(self::extractStablePart($currentDeviceHash));
1345
+ $stablePart = self::extractStablePart($currentDeviceHash);
1346
+ $stableFpId = !empty($stablePart) ? (string)FingerprintBuilder::cyrb53($stablePart) : (!empty($deviceId) ? $deviceId : (string)FingerprintBuilder::cyrb53($currentDeviceHash));
1330
1347
 
1331
1348
  $currentDeviceContributions = $subnetData['highScoreDevices'][$stableFpId] ?? 0;
1332
1349
  if ($currentDeviceContributions < 1 && $finalScore < 95) {
@@ -4,6 +4,10 @@ declare(strict_types=1);
4
4
 
5
5
  namespace Anonympins\Fingerprint\WordPress;
6
6
 
7
+ if (!defined('ABSPATH')) {
8
+ exit;
9
+ }
10
+
7
11
  use Anonympins\Fingerprint\Store\IStore;
8
12
 
9
13
  // Polyfill pour ARRAY_A si chargé hors du cycle de vie standard de WordPress