@anonympins/fingerprint 0.7.4 → 0.7.5

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 CHANGED
@@ -1,3 +1,30 @@
1
+ ## Version 0.7.5
2
+
3
+ - 🛡️ **Differential Privacy on Federated Threat Intelligence**:
4
+ - **Laplacian Noise on Federation Timestamps ($\text{Laplace}(0, b)$)**: Added mathematical perturbation to exact event timestamps in federated ban exchanges (`share_threat_intel`) parameterized by sensitivity $\Delta t = 5000\text{ms}$ and privacy budget $\epsilon$ (`differentialPrivacy.epsilon`). Timestamps are bounded within a safe $\pm 60\text{s}$ window to satisfy anti-replay checks while completely preventing malicious or compromised federation nodes from reconstructing inter-domain browsing trajectories via millisecond timing correlation.
5
+ - **Randomized Response Decoy Injection (Chaffing)**: Implemented randomized response logic where nodes inject and broadcast synthetic ZKP public keys generated uniformly in $\mathbb{Z}_p$ with probability $p = 1 / (1 + e^{\epsilon})$ (or customizable `dummyRate`). Due to the negligible collision probability of 256-bit keys ($\approx 2^{-256}$), decoys never reach the collaborative consensus threshold ($K \ge 3$), guaranteeing mathematical plausible deniability without causing false positives.
6
+ - **Multi-Runtime Parity**: Fully implemented across JavaScript (`fingerprint.js`), PHP (`FingerprintEngine.php`), Python (`engine.py`), and Java (`FingerprintEngine.java`, `FingerprintProperties.java`).
7
+
8
+ - 🌐 **Network Layer Anomaly Detection**:
9
+ - **MTU Anomaly Scoring (`mtuAnomalyScore`)**: Introduced `mtuAnomalyScore` to the suspicion vector and configuration weights across all runtimes. Evaluates passive TCP SYN options (specifically MSS — Maximum Segment Size) to detect anomalous MTU values typical of VPN/GRE tunneling, WireGuard encapsulation, or residential proxy backconnect chains attempting to masquerade as standard domestic browser connections.
10
+
11
+ - ♿ **Accessibility (a11y) & Invisible Honeypot Hardening**:
12
+ - **Screen-Reader Compliant Honeypot Fields**: Hardened dynamic DOM honeypot generation within `FingerprintClient` with `aria-hidden="true"`, `tabindex="-1"`, and `autocomplete="off"` attributes combined with defensive offscreen CSS positioning (`position: absolute; left: -9999px; transform: scale(0); opacity: 0; pointer-events: none;`). Ensures assistive technologies (NVDA, JAWS, VoiceOver) and browser autofill routines ignore honeypot inputs for visually impaired users while maintaining a 100% trap catch rate against automated scrapers.
13
+
14
+ - 🤖 **Crawler Whitelist Updates & Multi-Language Parity**:
15
+ - **Meta / Facebook Whitelist Addition**: Added dedicated IP subnets and CIDR definitions for Meta and Facebook crawlers (`facebookexternalhit`, `31.13.64.0/18`, `66.220.144.0/20`, `69.63.176.0/20`, `157.240.0.0/16`) to guarantee smooth link preview generation and indexing without challenge interruptions.
16
+ - **Cross-Platform Whitelist Synchronization**: Standardized crawler allowlists and DNS verification workflows (Googlebot, Bingbot, Yandex, Facebook) across all supported backend engines (Node.js, PHP, Python, and Java).
17
+
18
+ - 🔧 **Core Engine Refinements**:
19
+ - **`fingerprint.js` Updates**: Synchronized client-side metric collectors, refined behavioral input tracking, and plugged federation broadcast hooks directly into the core security pipeline.
20
+ - **Java Configuration Enhancements**: Added missing getters/setters and mapped configuration fields (`quicAnomalyScore`, `virtualizationScore`, `differentialPrivacy`, `federatedPeers`) in `FingerprintProperties.java`.
21
+ - **PHP Store Lifecycle**: Resolved initialization order edge cases for store instances during request processing in `FingerprintEngine.php`.
22
+
23
+ - 📖 **Documentation**:
24
+ - **Configuration Options Reference (`full_options.md`)**: Documented all new settings, including `mtuAnomalyScore`, `differentialPrivacy` block (`enabled`, `epsilon`, `dummyRate`), and federated threat sharing parameters.
25
+
26
+ ---
27
+
1
28
  ## Version 0.7.4
2
29
 
3
30
  - 🛡️ **Security & Rate Limiting**:
package/README.md CHANGED
@@ -91,7 +91,7 @@ In your **pom.xml**, add :
91
91
  <dependency>
92
92
  <groupId>com.anonympins</groupId>
93
93
  <artifactId>fingerprint-engine</artifactId>
94
- <version>0.7.4</version>
94
+ <version>0.7.5</version>
95
95
  </dependency>
96
96
  ```
97
97
  ## Documentation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anonympins/fingerprint",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "description": "Advanced anti-bot library for Node.js using multi-layer fingerprinting (JA3, client-side, headers), behavioral analysis, and adaptive Proof-of-Work (PoW) challenges to mitigate scraping, scalping, and automated threats.",
5
5
  "main": "index.js",
6
6
  "type": "module",
Binary file
@@ -1,219 +1,219 @@
1
- import crypto from "node:crypto";
2
-
3
- function encodeULEB128(val) {
4
- const bytes = [];
5
- let num = val >>> 0;
6
- do {
7
- let byte = num & 0x7f;
8
- num >>>= 7;
9
- if (num !== 0) byte |= 0x80;
10
- bytes.push(byte);
11
- } while (num !== 0);
12
- return bytes;
13
- }
14
-
15
- function encodeSLEB128(val) {
16
- const bytes = [];
17
- let num = val | 0;
18
- while (true) {
19
- let byte = num & 0x7f;
20
- num >>= 7;
21
- if ((num === 0 && (byte & 0x40) === 0) || (num === -1 && (byte & 0x40) !== 0)) {
22
- bytes.push(byte);
23
- break;
24
- }
25
- bytes.push(byte | 0x80);
26
- }
27
- return bytes;
28
- }
29
-
30
- function getRandomNonTrivialOpcodes(tempLocal) {
31
- const insts = [];
32
- const ops = [
33
- // local.get tempLocal, i32.const rand, rotl, local.set tempLocal
34
- () => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(1, 32)), 0x77, 0x21, tempLocal],
35
- // local.get tempLocal, i32.const rand, rotr, local.set tempLocal
36
- () => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(1, 32)), 0x78, 0x21, tempLocal],
37
- // local.get tempLocal, i32.const rand, xor, local.set tempLocal
38
- () => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(0, 10000)), 0x73, 0x21, tempLocal],
39
- // local.get tempLocal, popcnt, i32.const rand, mul, local.set tempLocal
40
- () => [0x20, tempLocal, 0x69, 0x41, ...encodeSLEB128(crypto.randomInt(1, 1001)), 0x6c, 0x21, tempLocal],
41
- // local.get tempLocal, clz, local.get tempLocal, ctz, add, local.set tempLocal
42
- () => [0x20, tempLocal, 0x67, 0x20, tempLocal, 0x68, 0x6a, 0x21, tempLocal]
43
- ];
44
- const count = crypto.randomInt(2, 5);
45
- for (let i = 0; i < count; i++) {
46
- const op = ops[crypto.randomInt(0, ops.length)];
47
- insts.push(...op());
48
- }
49
- return insts;
50
- }
51
-
52
- function generatePolymorphicInstructions(stateLocal = 4, tempLocal = 5) {
53
- const insts = [];
54
-
55
- // Initialize tempLocal with a random value
56
- const initVal = crypto.randomInt(-500, 500);
57
- insts.push(0x41, ...encodeSLEB128(initVal), 0x21, tempLocal);
58
-
59
- // Initialize stateLocal to 0
60
- insts.push(0x41, ...encodeSLEB128(0), 0x21, stateLocal);
61
-
62
- // Loop & Block for state machine
63
- insts.push(0x03, 0x40); // loop
64
- insts.push(0x02, 0x40); // block
65
-
66
- for (let state = 0; state < 3; state++) {
67
- insts.push(0x20, stateLocal, 0x41, ...encodeSLEB128(state), 0x46); // state == expected
68
- insts.push(0x04, 0x40); // if
69
- insts.push(...getRandomNonTrivialOpcodes(tempLocal));
70
- insts.push(0x41, ...encodeSLEB128(state + 1), 0x21, stateLocal); // transit to state + 1
71
- insts.push(0x0c, ...encodeULEB128(2)); // br 2 (targets loop start)
72
- insts.push(0x0b); // end if
73
- }
74
-
75
- // Fallthrough / Default break (targets block depth 0, which exits the loop)
76
- insts.push(0x0c, ...encodeULEB128(0));
77
-
78
- // end block
79
- insts.push(0x0b);
80
- // end loop
81
- insts.push(0x0b);
82
-
83
- return insts;
84
- }
85
-
86
- export class DynamicWasmGenerator {
87
- /**
88
- * Generates a unique polymorphic WebAssembly module containing a custom hash function
89
- * with randomized constants and control flow variables.
90
- * @param {object} constants - Custom seed, multiplier and adder.
91
- * @returns {Buffer} Valid WebAssembly binary buffer.
92
- */
93
- static generate(constants) {
94
- const { seed, multiplier, adder } = constants;
95
-
96
- const preLoopPoly = generatePolymorphicInstructions(4, 5);
97
- const midLoopPoly = generatePolymorphicInstructions(4, 5);
98
-
99
- const inst = [
100
- 0x01, 0x06, 0x7f, // Locals: 1 entry of 6 locals of type i32
101
- ...preLoopPoly,
102
- // h = seed
103
- 0x41, ...encodeSLEB128(seed),
104
- 0x21, 0x03,
105
- // i = 0
106
- 0x41, 0x00,
107
- 0x21, 0x02,
108
-
109
- // block
110
- 0x02, 0x40,
111
- // loop
112
- 0x03, 0x40,
113
-
114
- // if i >= len break
115
- 0x20, 0x02,
116
- 0x20, 0x01,
117
- 0x4f,
118
- 0x0d, 0x01,
119
-
120
- // byte = load8_u(ptr + i)
121
- 0x20, 0x00,
122
- 0x20, 0x02,
123
- 0x6a,
124
- 0x2d, 0x00, 0x00,
125
-
126
- // h = h ^ byte
127
- 0x20, 0x03,
128
- 0x73,
129
-
130
- // h = h * multiplier
131
- 0x41, ...encodeSLEB128(multiplier),
132
- 0x6c,
133
-
134
- // h = h + adder
135
- 0x41, ...encodeSLEB128(adder),
136
- 0x6a,
137
-
138
- // local.set 3
139
- 0x21, 0x03,
140
- ...midLoopPoly,
141
-
142
- // i = i + 1
143
- 0x20, 0x02,
144
- 0x41, 0x01,
145
- 0x6a,
146
- 0x21, 0x02,
147
-
148
- // br 0
149
- 0x0c, 0x00,
150
-
151
- 0x0b, // end loop
152
- 0x0b, // end block
153
-
154
- // return h
155
- 0x20, 0x03,
156
- 0x0b // end function
157
- ];
158
-
159
- const funcBody = [
160
- ...encodeULEB128(inst.length),
161
- ...inst
162
- ];
163
-
164
- const codeSectionPayload = [
165
- ...encodeULEB128(1),
166
- ...funcBody
167
- ];
168
-
169
- const codeSection = [
170
- 0x0a,
171
- ...encodeULEB128(codeSectionPayload.length),
172
- ...codeSectionPayload
173
- ];
174
-
175
- const typeSection = [
176
- 0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f
177
- ];
178
-
179
- const funcSection = [
180
- 0x03, 0x02, 0x01, 0x00
181
- ];
182
-
183
- const memSection = [
184
- 0x05, 0x03, 0x01, 0x00, 0x01
185
- ];
186
-
187
- const exportSection = [
188
- 0x07, 0x11, 0x02, 0x04, 0x68, 0x61, 0x73, 0x68, 0x00, 0x00, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00
189
- ];
190
-
191
- const wasm = [
192
- 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
193
- ...typeSection,
194
- ...funcSection,
195
- ...memSection,
196
- ...exportSection,
197
- ...codeSection
198
- ];
199
-
200
- return Buffer.from(wasm);
201
- }
202
-
203
- /**
204
- * Pure JavaScript fallback equivalent of the custom polymorphic hash.
205
- * @param {string} str Input string.
206
- * @param {object} constants Parameters.
207
- * @returns {number} 32-bit unsigned integer hash.
208
- */
209
- static hashJs(str, constants) {
210
- const { seed, multiplier, adder } = constants;
211
- let h = seed | 0;
212
- for (let i = 0; i < str.length; i++) {
213
- const byte = str.charCodeAt(i) & 0xff;
214
- h = h ^ byte;
215
- h = Math.imul(h, multiplier) + adder;
216
- }
217
- return h >>> 0;
218
- }
1
+ import crypto from "node:crypto";
2
+
3
+ function encodeULEB128(val) {
4
+ const bytes = [];
5
+ let num = val >>> 0;
6
+ do {
7
+ let byte = num & 0x7f;
8
+ num >>>= 7;
9
+ if (num !== 0) byte |= 0x80;
10
+ bytes.push(byte);
11
+ } while (num !== 0);
12
+ return bytes;
13
+ }
14
+
15
+ function encodeSLEB128(val) {
16
+ const bytes = [];
17
+ let num = val | 0;
18
+ while (true) {
19
+ let byte = num & 0x7f;
20
+ num >>= 7;
21
+ if ((num === 0 && (byte & 0x40) === 0) || (num === -1 && (byte & 0x40) !== 0)) {
22
+ bytes.push(byte);
23
+ break;
24
+ }
25
+ bytes.push(byte | 0x80);
26
+ }
27
+ return bytes;
28
+ }
29
+
30
+ function getRandomNonTrivialOpcodes(tempLocal) {
31
+ const insts = [];
32
+ const ops = [
33
+ // local.get tempLocal, i32.const rand, rotl, local.set tempLocal
34
+ () => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(1, 32)), 0x77, 0x21, tempLocal],
35
+ // local.get tempLocal, i32.const rand, rotr, local.set tempLocal
36
+ () => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(1, 32)), 0x78, 0x21, tempLocal],
37
+ // local.get tempLocal, i32.const rand, xor, local.set tempLocal
38
+ () => [0x20, tempLocal, 0x41, ...encodeSLEB128(crypto.randomInt(0, 10000)), 0x73, 0x21, tempLocal],
39
+ // local.get tempLocal, popcnt, i32.const rand, mul, local.set tempLocal
40
+ () => [0x20, tempLocal, 0x69, 0x41, ...encodeSLEB128(crypto.randomInt(1, 1001)), 0x6c, 0x21, tempLocal],
41
+ // local.get tempLocal, clz, local.get tempLocal, ctz, add, local.set tempLocal
42
+ () => [0x20, tempLocal, 0x67, 0x20, tempLocal, 0x68, 0x6a, 0x21, tempLocal]
43
+ ];
44
+ const count = crypto.randomInt(2, 5);
45
+ for (let i = 0; i < count; i++) {
46
+ const op = ops[crypto.randomInt(0, ops.length)];
47
+ insts.push(...op());
48
+ }
49
+ return insts;
50
+ }
51
+
52
+ function generatePolymorphicInstructions(stateLocal = 4, tempLocal = 5) {
53
+ const insts = [];
54
+
55
+ // Initialize tempLocal with a random value
56
+ const initVal = crypto.randomInt(-500, 500);
57
+ insts.push(0x41, ...encodeSLEB128(initVal), 0x21, tempLocal);
58
+
59
+ // Initialize stateLocal to 0
60
+ insts.push(0x41, ...encodeSLEB128(0), 0x21, stateLocal);
61
+
62
+ // Loop & Block for state machine
63
+ insts.push(0x03, 0x40); // loop
64
+ insts.push(0x02, 0x40); // block
65
+
66
+ for (let state = 0; state < 3; state++) {
67
+ insts.push(0x20, stateLocal, 0x41, ...encodeSLEB128(state), 0x46); // state == expected
68
+ insts.push(0x04, 0x40); // if
69
+ insts.push(...getRandomNonTrivialOpcodes(tempLocal));
70
+ insts.push(0x41, ...encodeSLEB128(state + 1), 0x21, stateLocal); // transit to state + 1
71
+ insts.push(0x0c, ...encodeULEB128(2)); // br 2 (targets loop start)
72
+ insts.push(0x0b); // end if
73
+ }
74
+
75
+ // Fallthrough / Default break (targets block depth 0, which exits the loop)
76
+ insts.push(0x0c, ...encodeULEB128(0));
77
+
78
+ // end block
79
+ insts.push(0x0b);
80
+ // end loop
81
+ insts.push(0x0b);
82
+
83
+ return insts;
84
+ }
85
+
86
+ export class DynamicWasmGenerator {
87
+ /**
88
+ * Generates a unique polymorphic WebAssembly module containing a custom hash function
89
+ * with randomized constants and control flow variables.
90
+ * @param {object} constants - Custom seed, multiplier and adder.
91
+ * @returns {Buffer} Valid WebAssembly binary buffer.
92
+ */
93
+ static generate(constants) {
94
+ const { seed, multiplier, adder } = constants;
95
+
96
+ const preLoopPoly = generatePolymorphicInstructions(4, 5);
97
+ const midLoopPoly = generatePolymorphicInstructions(4, 5);
98
+
99
+ const inst = [
100
+ 0x01, 0x06, 0x7f, // Locals: 1 entry of 6 locals of type i32
101
+ ...preLoopPoly,
102
+ // h = seed
103
+ 0x41, ...encodeSLEB128(seed),
104
+ 0x21, 0x03,
105
+ // i = 0
106
+ 0x41, 0x00,
107
+ 0x21, 0x02,
108
+
109
+ // block
110
+ 0x02, 0x40,
111
+ // loop
112
+ 0x03, 0x40,
113
+
114
+ // if i >= len break
115
+ 0x20, 0x02,
116
+ 0x20, 0x01,
117
+ 0x4f,
118
+ 0x0d, 0x01,
119
+
120
+ // byte = load8_u(ptr + i)
121
+ 0x20, 0x00,
122
+ 0x20, 0x02,
123
+ 0x6a,
124
+ 0x2d, 0x00, 0x00,
125
+
126
+ // h = h ^ byte
127
+ 0x20, 0x03,
128
+ 0x73,
129
+
130
+ // h = h * multiplier
131
+ 0x41, ...encodeSLEB128(multiplier),
132
+ 0x6c,
133
+
134
+ // h = h + adder
135
+ 0x41, ...encodeSLEB128(adder),
136
+ 0x6a,
137
+
138
+ // local.set 3
139
+ 0x21, 0x03,
140
+ ...midLoopPoly,
141
+
142
+ // i = i + 1
143
+ 0x20, 0x02,
144
+ 0x41, 0x01,
145
+ 0x6a,
146
+ 0x21, 0x02,
147
+
148
+ // br 0
149
+ 0x0c, 0x00,
150
+
151
+ 0x0b, // end loop
152
+ 0x0b, // end block
153
+
154
+ // return h
155
+ 0x20, 0x03,
156
+ 0x0b // end function
157
+ ];
158
+
159
+ const funcBody = [
160
+ ...encodeULEB128(inst.length),
161
+ ...inst
162
+ ];
163
+
164
+ const codeSectionPayload = [
165
+ ...encodeULEB128(1),
166
+ ...funcBody
167
+ ];
168
+
169
+ const codeSection = [
170
+ 0x0a,
171
+ ...encodeULEB128(codeSectionPayload.length),
172
+ ...codeSectionPayload
173
+ ];
174
+
175
+ const typeSection = [
176
+ 0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f
177
+ ];
178
+
179
+ const funcSection = [
180
+ 0x03, 0x02, 0x01, 0x00
181
+ ];
182
+
183
+ const memSection = [
184
+ 0x05, 0x03, 0x01, 0x00, 0x01
185
+ ];
186
+
187
+ const exportSection = [
188
+ 0x07, 0x11, 0x02, 0x04, 0x68, 0x61, 0x73, 0x68, 0x00, 0x00, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00
189
+ ];
190
+
191
+ const wasm = [
192
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
193
+ ...typeSection,
194
+ ...funcSection,
195
+ ...memSection,
196
+ ...exportSection,
197
+ ...codeSection
198
+ ];
199
+
200
+ return Buffer.from(wasm);
201
+ }
202
+
203
+ /**
204
+ * Pure JavaScript fallback equivalent of the custom polymorphic hash.
205
+ * @param {string} str Input string.
206
+ * @param {object} constants Parameters.
207
+ * @returns {number} 32-bit unsigned integer hash.
208
+ */
209
+ static hashJs(str, constants) {
210
+ const { seed, multiplier, adder } = constants;
211
+ let h = seed | 0;
212
+ for (let i = 0; i < str.length; i++) {
213
+ const byte = str.charCodeAt(i) & 0xff;
214
+ h = h ^ byte;
215
+ h = Math.imul(h, multiplier) + adder;
216
+ }
217
+ return h >>> 0;
218
+ }
219
219
  }