@anonympins/fingerprint 0.4.4 → 0.4.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 +40 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/js/dynamic-wasm.js +180 -0
- package/src/js/fingerprint.client.js +21 -0
- package/src/js/fingerprint.js +763 -56
- package/src/js/library.js +1740 -1729
- package/src/js/pow.solver.inline.js +381 -285
- package/src/js/pow.solver.js +97 -1
- package/src/js/tests/dynamic-wasm.test.js +78 -0
- package/src/js/tests/fingerprint.client.test.js +128 -104
- package/src/js/tests/fingerprint.test.js +79 -1
- package/src/js/tests/ip-reputation.test.js +141 -131
- package/src/js/tests/tcpFingerprint.test.js +78 -0
- package/src/php/AutoTuner.php +1 -1
- package/src/php/Challenge/ChallengeUtils.php +174 -12
- package/src/php/Config/SecurityProfiles.php +10 -0
- package/src/php/FingerprintEngine.php +140 -8
- package/src/php/Optimization/Optimization.php +257 -255
- package/src/php/Optimization/OptimizationOperators.php +41 -35
- package/src/php/RequestContext.php +2 -0
- package/src/php/Tests/FingerprintEngineTest.php +132 -1
- package/src/php/Tests/IpReputationTest.php +175 -156
- package/src/php/Tests/RequestUtilsTest.php +13 -0
- package/src/php/Utils/RequestUtils.php +319 -5
|
@@ -1,256 +1,258 @@
|
|
|
1
|
-
<?php
|
|
2
|
-
|
|
3
|
-
declare(strict_types=1);
|
|
4
|
-
|
|
5
|
-
namespace Anonympins\Fingerprint\Optimization;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Bibliothèque d'algorithmes d'optimisation.
|
|
9
|
-
*/
|
|
10
|
-
class Optimization
|
|
11
|
-
{
|
|
12
|
-
/**
|
|
13
|
-
* Génère un nombre flottant aléatoire cryptographiquement sûr entre 0 (inclus) et 1 (exclus).
|
|
14
|
-
*/
|
|
15
|
-
private static function secureRandom(): float
|
|
16
|
-
{
|
|
17
|
-
try {
|
|
18
|
-
return random_int(0, PHP_INT_MAX - 1) / PHP_INT_MAX;
|
|
19
|
-
} catch (\Exception $e) {
|
|
20
|
-
return (float)mt_rand() / (float)mt_getrandmax(); // Fallback
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Algorithme génétique multi-objectifs (inspiré de NSGA-II).
|
|
26
|
-
* @param callable $createIndividual
|
|
27
|
-
* @param callable $fitnessFunction
|
|
28
|
-
* @param callable $crossover
|
|
29
|
-
* @param callable $mutate
|
|
30
|
-
* @param array $
|
|
31
|
-
* @
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
callable $
|
|
36
|
-
callable $
|
|
37
|
-
callable $
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
$
|
|
41
|
-
|
|
42
|
-
$
|
|
43
|
-
|
|
44
|
-
$
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
$
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
$
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
*
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
*
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
$p1
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
$p1['
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
$
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
*
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
$
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
$
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace Anonympins\Fingerprint\Optimization;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Bibliothèque d'algorithmes d'optimisation.
|
|
9
|
+
*/
|
|
10
|
+
class Optimization
|
|
11
|
+
{
|
|
12
|
+
/**
|
|
13
|
+
* Génère un nombre flottant aléatoire cryptographiquement sûr entre 0 (inclus) et 1 (exclus).
|
|
14
|
+
*/
|
|
15
|
+
private static function secureRandom(): float
|
|
16
|
+
{
|
|
17
|
+
try {
|
|
18
|
+
return random_int(0, PHP_INT_MAX - 1) / PHP_INT_MAX;
|
|
19
|
+
} catch (\Exception $e) {
|
|
20
|
+
return (float)mt_rand() / (float)mt_getrandmax(); // Fallback
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Algorithme génétique multi-objectifs (inspiré de NSGA-II).
|
|
26
|
+
* @param callable $createIndividual
|
|
27
|
+
* @param callable $fitnessFunction
|
|
28
|
+
* @param callable $crossover
|
|
29
|
+
* @param callable $mutate
|
|
30
|
+
* @param array|null $currentConfig La configuration actuelle pour guider l'initialisation et la mutation.
|
|
31
|
+
* @param array $options
|
|
32
|
+
* @return array<int, array{solution: mixed, objectives: array<float>}>
|
|
33
|
+
*/
|
|
34
|
+
public static function geneticAlgorithmMultiObjective(
|
|
35
|
+
callable $createIndividual,
|
|
36
|
+
callable $fitnessFunction,
|
|
37
|
+
callable $crossover,
|
|
38
|
+
callable $mutate, // La fonction mutate doit maintenant accepter $currentConfig
|
|
39
|
+
?array $currentConfig = null, // NOUVEAU: La configuration actuelle
|
|
40
|
+
array $options = []
|
|
41
|
+
): array {
|
|
42
|
+
$generations = $options['generations'] ?? 150;
|
|
43
|
+
$populationSize = $options['populationSize'] ?? 60;
|
|
44
|
+
$mutationRate = $options['mutationRate'] ?? 0.1;
|
|
45
|
+
|
|
46
|
+
$population = [];
|
|
47
|
+
for ($i = 0; $i < $populationSize; $i++) {
|
|
48
|
+
$individual = $createIndividual();
|
|
49
|
+
$population[] = [
|
|
50
|
+
'individual' => $individual,
|
|
51
|
+
'objectives' => $fitnessFunction($individual)
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for ($gen = 0; $gen < $generations; $gen++) {
|
|
56
|
+
// 1. Créer une population d'enfants
|
|
57
|
+
$offspring = [];
|
|
58
|
+
for ($i = 0; $i < $populationSize; $i++) {
|
|
59
|
+
$parent1 = $population[random_int(0, count($population) - 1)];
|
|
60
|
+
$parent2 = $population[random_int(0, count($population) - 1)];
|
|
61
|
+
$childIndividual = $crossover($parent1['individual'], $parent2['individual']);
|
|
62
|
+
if (self::secureRandom() < $mutationRate) {
|
|
63
|
+
$childIndividual = $mutate($childIndividual, $currentConfig); // Passer $currentConfig à mutate
|
|
64
|
+
}
|
|
65
|
+
$offspring[] = [
|
|
66
|
+
'individual' => $childIndividual,
|
|
67
|
+
'objectives' => $fitnessFunction($childIndividual)
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 2. Combiner parents et enfants
|
|
72
|
+
$combinedPopulation = array_merge($population, $offspring);
|
|
73
|
+
|
|
74
|
+
// 3. Trier la population combinée en fronts
|
|
75
|
+
$fronts = self::nonDominatedSort($combinedPopulation);
|
|
76
|
+
|
|
77
|
+
// 4. Construire la nouvelle population
|
|
78
|
+
$newPopulation = [];
|
|
79
|
+
foreach ($fronts as $front) {
|
|
80
|
+
if (count($newPopulation) + count($front) <= $populationSize) {
|
|
81
|
+
$newPopulation = array_merge($newPopulation, $front);
|
|
82
|
+
} else {
|
|
83
|
+
self::calculateCrowdingDistance($front);
|
|
84
|
+
// Trier par distance décroissante
|
|
85
|
+
usort($front, fn ($a, $b) => $b['crowdingDistance'] <=> $a['crowdingDistance']);
|
|
86
|
+
$remaining = $populationSize - count($newPopulation);
|
|
87
|
+
$newPopulation = array_merge($newPopulation, array_slice($front, 0, $remaining));
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
$population = $newPopulation;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Retourner le premier front de la population finale
|
|
95
|
+
$finalFronts = self::nonDominatedSort($population);
|
|
96
|
+
$bestFront = $finalFronts[0] ?? [];
|
|
97
|
+
|
|
98
|
+
// Filtrer pour ne garder que les solutions avec des objectifs uniques
|
|
99
|
+
$uniqueSolutionsMap = [];
|
|
100
|
+
foreach ($bestFront as $p) {
|
|
101
|
+
$key = json_encode($p['objectives']);
|
|
102
|
+
if (!isset($uniqueSolutionsMap[$key])) {
|
|
103
|
+
$uniqueSolutionsMap[$key] = [
|
|
104
|
+
'solution' => $p['individual'],
|
|
105
|
+
'objectives' => $p['objectives'],
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return array_values($uniqueSolutionsMap);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Détermine si la solution A domine la solution B.
|
|
114
|
+
* @param array<float> $objectivesA
|
|
115
|
+
* @param array<float> $objectivesB
|
|
116
|
+
*/
|
|
117
|
+
private static function paretoDominates(array $objectivesA, array $objectivesB): bool
|
|
118
|
+
{
|
|
119
|
+
$aIsBetterInOne = false;
|
|
120
|
+
for ($i = 0; $i < count($objectivesA); $i++) {
|
|
121
|
+
if ($objectivesA[$i] > $objectivesB[$i]) {
|
|
122
|
+
return false; // A est pire sur au moins un objectif
|
|
123
|
+
}
|
|
124
|
+
if ($objectivesA[$i] < $objectivesB[$i]) {
|
|
125
|
+
$aIsBetterInOne = true; // A est strictement meilleur sur au moins un
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return $aIsBetterInOne;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Trie une population en fronts de Pareto non-dominés.
|
|
133
|
+
* @param array<int, array> &$populationWithObjectives
|
|
134
|
+
* @return array<int, array>
|
|
135
|
+
*/
|
|
136
|
+
private static function nonDominatedSort(array &$populationWithObjectives): array
|
|
137
|
+
{
|
|
138
|
+
$fronts = [[]];
|
|
139
|
+
$n = count($populationWithObjectives);
|
|
140
|
+
|
|
141
|
+
for ($i = 0; $i < $n; $i++) {
|
|
142
|
+
$p1 = &$populationWithObjectives[$i];
|
|
143
|
+
$p1['dominationCount'] = 0;
|
|
144
|
+
$p1['dominatedSolutions'] = [];
|
|
145
|
+
|
|
146
|
+
for ($j = 0; $j < $n; $j++) {
|
|
147
|
+
if ($i === $j) continue;
|
|
148
|
+
$p2 = &$populationWithObjectives[$j];
|
|
149
|
+
|
|
150
|
+
if (self::paretoDominates($p1['objectives'], $p2['objectives'])) {
|
|
151
|
+
$p1['dominatedSolutions'][] = $j;
|
|
152
|
+
} elseif (self::paretoDominates($p2['objectives'], $p1['objectives'])) {
|
|
153
|
+
$p1['dominationCount']++;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if ($p1['dominationCount'] === 0) {
|
|
158
|
+
$p1['rank'] = 0;
|
|
159
|
+
$fronts[0][] = $p1;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
$i = 0;
|
|
164
|
+
while (!empty($fronts[$i])) {
|
|
165
|
+
$nextFront = [];
|
|
166
|
+
foreach ($fronts[$i] as $p1) {
|
|
167
|
+
foreach ($p1['dominatedSolutions'] as $p2_idx) {
|
|
168
|
+
$p2 = &$populationWithObjectives[$p2_idx];
|
|
169
|
+
$p2['dominationCount']--;
|
|
170
|
+
if ($p2['dominationCount'] === 0) {
|
|
171
|
+
$p2['rank'] = $i + 1;
|
|
172
|
+
$nextFront[] = $p2;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
$i++;
|
|
177
|
+
if (!empty($nextFront)) {
|
|
178
|
+
$fronts[$i] = $nextFront;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return $fronts;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Calcule la distance de promiscuité (crowding distance) pour un front.
|
|
186
|
+
* @param array<int, array> &$front
|
|
187
|
+
*/
|
|
188
|
+
private static function calculateCrowdingDistance(array &$front): void
|
|
189
|
+
{
|
|
190
|
+
if (empty($front)) return;
|
|
191
|
+
|
|
192
|
+
$numObjectives = count($front[0]['objectives']);
|
|
193
|
+
$l = count($front);
|
|
194
|
+
|
|
195
|
+
foreach ($front as &$p) {
|
|
196
|
+
$p['crowdingDistance'] = 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
for ($i = 0; $i < $numObjectives; $i++) {
|
|
200
|
+
// Trier le front par l'objectif courant
|
|
201
|
+
usort($front, fn ($a, $b) => $a['objectives'][$i] <=> $b['objectives'][$i]);
|
|
202
|
+
|
|
203
|
+
$minObj = $front[0]['objectives'][$i];
|
|
204
|
+
$maxObj = $front[$l - 1]['objectives'][$i];
|
|
205
|
+
|
|
206
|
+
// Les solutions aux extrémités ont une distance infinie
|
|
207
|
+
$front[0]['crowdingDistance'] = INF;
|
|
208
|
+
$front[$l - 1]['crowdingDistance'] = INF;
|
|
209
|
+
|
|
210
|
+
if ($maxObj === $minObj) continue;
|
|
211
|
+
|
|
212
|
+
for ($j = 1; $j < $l - 1; $j++) {
|
|
213
|
+
$front[$j]['crowdingDistance'] +=
|
|
214
|
+
($front[$j + 1]['objectives'][$i] - $front[$j - 1]['objectives'][$i]) /
|
|
215
|
+
($maxObj - $minObj);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Calcule la déviation d'une série de chiffres par rapport à la loi de Benford.
|
|
222
|
+
* @public
|
|
223
|
+
* @param array<int|float> $numbers
|
|
224
|
+
*/
|
|
225
|
+
public static function benfordTest(array $numbers): float // Rendre la méthode publique et statique
|
|
226
|
+
{
|
|
227
|
+
if (count($numbers) < 10) {
|
|
228
|
+
return 0.0; // Pas assez de données
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
$leadingDigits = array_map(function ($n) {
|
|
232
|
+
$str = ltrim((string)$n, '0.');
|
|
233
|
+
return $str[0] ?? '';
|
|
234
|
+
}, $numbers);
|
|
235
|
+
|
|
236
|
+
$leadingDigits = array_filter($leadingDigits, fn ($d) => $d >= '1' && $d <= '9');
|
|
237
|
+
|
|
238
|
+
if (count($leadingDigits) < 10) {
|
|
239
|
+
return 0.0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
$counts = array_fill(1, 9, 0);
|
|
243
|
+
foreach ($leadingDigits as $digit) {
|
|
244
|
+
$counts[(int)$digit]++;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
$benfordDistribution = [1 => 30.1, 2 => 17.6, 3 => 12.5, 4 => 9.7, 5 => 7.9, 6 => 6.7, 7 => 5.8, 8 => 5.1, 9 => 4.6];
|
|
248
|
+
|
|
249
|
+
$totalDeviation = 0.0;
|
|
250
|
+
for ($i = 1; $i <= 9; $i++) {
|
|
251
|
+
$observedFrequency = ($counts[$i] / count($leadingDigits)) * 100;
|
|
252
|
+
$expectedFrequency = $benfordDistribution[$i];
|
|
253
|
+
$totalDeviation += pow($observedFrequency - $expectedFrequency, 2);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return sqrt($totalDeviation) / 50.0;
|
|
257
|
+
}
|
|
256
258
|
}
|
|
@@ -104,39 +104,6 @@ class OptimizationOperators
|
|
|
104
104
|
{
|
|
105
105
|
$fitnessFunction = self::createFullSecurityConfigEvaluator($context);
|
|
106
106
|
|
|
107
|
-
$createIndividual = function (): array {
|
|
108
|
-
return [
|
|
109
|
-
'thresholds' => [
|
|
110
|
-
'low' => 15 + self::secureRandom() * 20,
|
|
111
|
-
'medium' => 40 + self::secureRandom() * 25,
|
|
112
|
-
'high' => 70 + self::secureRandom() * 20,
|
|
113
|
-
],
|
|
114
|
-
'weights' => [
|
|
115
|
-
'historyScore' => self::secureRandom(),
|
|
116
|
-
'rotationScore' => self::secureRandom(),
|
|
117
|
-
'headerAnomalyScore' => self::secureRandom(),
|
|
118
|
-
'requestPatternScore' => 0.5 + self::secureRandom(),
|
|
119
|
-
'inconsistencyScore' => self::secureRandom(),
|
|
120
|
-
'honeypotScore' => 1.0,
|
|
121
|
-
'behaviorScore' => self::secureRandom(),
|
|
122
|
-
'crossLayerInconsistencyScore' => self::secureRandom(),
|
|
123
|
-
'timeInconsistencyScore' => self::secureRandom(),
|
|
124
|
-
'tlsSpoofingScore' => self::secureRandom(),
|
|
125
|
-
'botScore' => self::secureRandom(),
|
|
126
|
-
'cookieDroppingScore' => self::secureRandom(),
|
|
127
|
-
'threatIntelScore' => self::secureRandom(),
|
|
128
|
-
],
|
|
129
|
-
'patterns' => [
|
|
130
|
-
'velocityThreshold' => 100 + self::secureRandom() * 400,
|
|
131
|
-
'burstThreshold' => 300 + self::secureRandom() * 700,
|
|
132
|
-
'scrapeThreshold' => 500 + self::secureRandom() * 1000,
|
|
133
|
-
'regularityThreshold' => 50 + self::secureRandom() * 200,
|
|
134
|
-
'decayFactor' => 0.85 + self::secureRandom() * 0.14,
|
|
135
|
-
'inactivityReset' => 15000 + self::secureRandom() * 45000,
|
|
136
|
-
]
|
|
137
|
-
];
|
|
138
|
-
};
|
|
139
|
-
|
|
140
107
|
$crossover = function (array $c1, array $c2): array {
|
|
141
108
|
$child = $c1;
|
|
142
109
|
foreach (['thresholds', 'weights', 'patterns'] as $section) {
|
|
@@ -148,8 +115,35 @@ class OptimizationOperators
|
|
|
148
115
|
}
|
|
149
116
|
return $child;
|
|
150
117
|
};
|
|
118
|
+
$createIndividual = function () use ($currentConfig): array {
|
|
119
|
+
if ($currentConfig) {
|
|
120
|
+
$ind = [
|
|
121
|
+
'thresholds' => [],
|
|
122
|
+
'weights' => [],
|
|
123
|
+
'patterns' => []
|
|
124
|
+
];
|
|
125
|
+
foreach (['thresholds', 'weights', 'patterns'] as $section) {
|
|
126
|
+
if (isset($currentConfig[$section]) && is_array($currentConfig[$section])) {
|
|
127
|
+
foreach ($currentConfig[$section] as $k => $v) {
|
|
128
|
+
if (is_numeric($v) && $k !== 'honeypotScore') {
|
|
129
|
+
$randomVariation = 1.0 + (self::secureRandom() - 0.5) * 0.5; // Variation de +/- 25%
|
|
130
|
+
$ind[$section][$k] = $v * $randomVariation;
|
|
131
|
+
} else {
|
|
132
|
+
$ind[$section][$k] = $v;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (isset($ind['thresholds']['low'], $ind['thresholds']['medium'], $ind['thresholds']['high'])) {
|
|
138
|
+
$ind['thresholds']['low'] = max(10.0, min(35.0, (float)$ind['thresholds']['low']));
|
|
139
|
+
$ind['thresholds']['medium'] = max($ind['thresholds']['low'] + 5.0, min(70.0, (float)$ind['thresholds']['medium']));
|
|
140
|
+
$ind['thresholds']['high'] = max($ind['thresholds']['medium'] + 5.0, min(90.0, (float)$ind['thresholds']['high']));
|
|
141
|
+
}
|
|
142
|
+
return $ind;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
151
145
|
|
|
152
|
-
$mutate = function (array $c): array {
|
|
146
|
+
$mutate = function (array $c, ?array $currentConfigRef = null) use ($currentConfig): array {
|
|
153
147
|
$newConfig = $c;
|
|
154
148
|
$sections = [
|
|
155
149
|
['name' => 'patterns', 'weight' => 0.5],
|
|
@@ -179,15 +173,27 @@ class OptimizationOperators
|
|
|
179
173
|
$newConfig[$sectionToMutate][$keyToMutate] = max(0, min(1.5, $newConfig[$sectionToMutate][$keyToMutate]));
|
|
180
174
|
}
|
|
181
175
|
|
|
176
|
+
$refConfig = $currentConfigRef ?? $currentConfig;
|
|
177
|
+
if ($refConfig && isset($refConfig[$sectionToMutate][$keyToMutate])) {
|
|
178
|
+
$originalValue = $refConfig[$sectionToMutate][$keyToMutate];
|
|
179
|
+
if (is_numeric($originalValue) && $originalValue != 0) {
|
|
180
|
+
$minAllowed = $originalValue * 0.7; // -30%
|
|
181
|
+
$maxAllowed = $originalValue * 1.3; // +30%
|
|
182
|
+
$newConfig[$sectionToMutate][$keyToMutate] = max($minAllowed, min($maxAllowed, $newConfig[$sectionToMutate][$keyToMutate]));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
182
186
|
return $newConfig;
|
|
183
187
|
};
|
|
188
|
+
$gaOptions = array_merge(['generations' => 50, 'populationSize' => 50], $options);
|
|
184
189
|
|
|
185
190
|
return Optimization::geneticAlgorithmMultiObjective(
|
|
186
191
|
$createIndividual,
|
|
187
192
|
$fitnessFunction,
|
|
188
193
|
$crossover,
|
|
189
194
|
$mutate,
|
|
190
|
-
|
|
195
|
+
$currentConfig,
|
|
196
|
+
$gaOptions
|
|
191
197
|
);
|
|
192
198
|
}
|
|
193
199
|
|
|
@@ -24,6 +24,7 @@ class RequestContext
|
|
|
24
24
|
public array $cookies = [];
|
|
25
25
|
public ?string $httpVersion = null;
|
|
26
26
|
public int $requestTimestamp = 0;
|
|
27
|
+
public ?string $tlsSessionId = null;
|
|
27
28
|
|
|
28
29
|
/** @var ?array{type: string, name: string} */
|
|
29
30
|
public ?array $graphqlOperation = null;
|
|
@@ -76,6 +77,7 @@ class RequestContext
|
|
|
76
77
|
$this->ja4h = $this->headers['x-ja4h-hash'] ?? null;
|
|
77
78
|
$this->http2Fingerprint = $this->headers['x-http2-fingerprint'] ?? null;
|
|
78
79
|
$this->tcpFingerprint = $this->headers['x-tcp-fingerprint'] ?? null;
|
|
80
|
+
$this->tlsSessionId = $this->headers['x-tls-session-id'] ?? $this->headers['x-ssl-session-id'] ?? null;
|
|
79
81
|
}
|
|
80
82
|
/**
|
|
81
83
|
* Récupère la valeur d'un en-tête HTTP de manière insensible à la casse.
|