@anonympins/fingerprint 0.4.6 → 0.5.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 +21 -0
- package/README.md +56 -11
- package/package.json +2 -1
- package/src/js/fingerprint.client.js +139 -0
- package/src/js/fingerprint.js +360 -191
- package/src/js/fingerprint.utils.js +184 -0
- package/src/js/library.js +1 -1
- package/src/js/pow.solver.inline.js +12 -4
- package/src/js/pow.solver.js +12 -4
- package/src/js/tests/fingerprint.isMalicious.test.js +234 -116
- package/src/js/tests/fingerprint.test.js +132 -1
- package/src/js/tests/ja3AnomalyDetector.test.js +1 -0
- package/src/php/AutoTuner.php +71 -0
- package/src/php/Challenge/ChallengeUtils.php +302 -9
- package/src/php/FingerprintEngine.php +40 -2
- package/src/php/Tests/ChallengeUtilsTest.php +208 -81
- package/src/php/Tests/MaliciousPatternsTest.php +104 -0
- package/src/php/Utils/BigInt.php +202 -144
- package/src/php/Utils/MaliciousPatterns.php +74 -58
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## Version 0.5.0
|
|
2
|
+
|
|
3
|
+
### ✨ New Features
|
|
4
|
+
|
|
5
|
+
- **Zero-Knowledge Proofs (ZKP)**: Added cryptographically secure Schnorr Zero-Knowledge Proofs (`generateZkpProof` on client and `verifyZkpProof` on server) for device fingerprints, allowing zero-disclosure fingerprint validation and making session tickets completely tamper-proof.
|
|
6
|
+
- **Optional Ed25519 Asymmetric Keys**: Implemented dynamic and optional Ed25519 asymmetric key binding with an automatic fallback to symmetric AES-256-CBC encryption.
|
|
7
|
+
- **Cooperative Proof-of-Space (Coop PoSpace)**: Introduced decentralized, cooperative Proof-of-Space challenge routing within local subnets. Highly suspicious clients must coordinate with neighboring subnet peers to fetch and aggregate cryptographic blocks. This vastly increases the cost and complexity for distributed botnets trying to cycle residential proxy IPs, as they are forced to run and maintain real, synchronized, and cooperative peer nodes within the same local IP subnet to solve challenges.
|
|
8
|
+
|
|
9
|
+
### 🚀 Improvements
|
|
10
|
+
|
|
11
|
+
- **Enhanced Malicious Injection Detection**: Upgraded the WAF and input validation subsystem to recursively inspect deeply nested NoSQL/SQL structures, significantly improving protection against complex MongoDb/SQL injection vectors.
|
|
12
|
+
- **Traffic Data Pruning**: Introduced automated traffic data pruning (`pruneTrafficData`) with time-based and size-based limiters to avoid memory leaks during long-running auto-tuning sessions.
|
|
13
|
+
|
|
14
|
+
### 🐛 Bug Fixes
|
|
15
|
+
|
|
16
|
+
- **CI/CD OpenSSL Compatibility**: Fixed test environment crashes on older systems or CI/CD pipelines where the `OPENSSL_KEYTYPE_ED25519` constant is undefined.
|
|
17
|
+
- **Autoloader savePath Resolution**: Resolved file-system path resolution bugs when saving optimized configurations inside the auto-tuner.
|
|
18
|
+
- **Repository Size Optimization**: Pruned obsolete resources and optimized package assets to significantly reduce overall repository footprint.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
1
22
|
## Version 0.4.6
|
|
2
23
|
|
|
3
24
|
### ✨ New Features
|
package/README.md
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
# Fingerprint anti-bot protection
|
|
2
2
|
|
|
3
|
-
NodeJS tests : [](https://github.com/anonympins/fingerprint/actions/workflows/ci-nodejs.yml) / PHP tests : [](https://github.com/anonympins/fingerprint/actions/workflows/ci-php.yml) / Python tests : [](https://github.com/anonympins/fingerprint/actions/workflows/ci-python.yml)
|
|
4
4
|
|
|
5
|
-
[](https://github.com/anonympins/fingerprint/releases)
|
|
6
|
+
[](https://github.com/anonympins/fingerprint/blob/main/LICENSE)
|
|
7
|
+
[](https://github.com/anonympins/fingerprint/commits/main)
|
|
8
|
+
[](https://github.com/anonympins/fingerprint)
|
|
8
9
|
|
|
9
|
-
A multi-layered behavioral, cryptographic, and network analysis engine designed to identify and mitigate malicious requests (bots, scrapers, session hijacking, bot farms) in real-time. Supports **Node.js**, **Python** and **PHP** environments.
|
|
10
|
+
A multi-layered behavioral, cryptographic, and network analysis production-grade engine designed to identify and mitigate malicious requests (bots, scrapers, session hijacking, bot farms) in real-time. Supports **Node.js**, **Python** and **PHP** environments.
|
|
11
|
+
|
|
12
|
+
It leverages multi-layer hardware fingerprinting, real-time behavioral analysis, passive network/TLS tracking, and adaptive/useful proof-of-work challenges to dynamically detect and mitigate scraping, scalping, account takeover (ATO), and sophisticated automated threats.
|
|
13
|
+
|
|
14
|
+
Supported officially on **Node.js (>=20.0.0)**, **PHP (>=8.0)**, and **Python (>=3.8)**.
|
|
10
15
|
|
|
11
16
|

|
|
12
17
|
|
|
@@ -14,11 +19,42 @@ A multi-layered behavioral, cryptographic, and network analysis engine designed
|
|
|
14
19
|
|
|
15
20
|
[](https://www.youtube.com/watch?v=Ujeznl0JAl4)
|
|
16
21
|
|
|
17
|
-
## Key Features
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
## 🚀 Key Features
|
|
24
|
+
|
|
25
|
+
### 1. 🧬 Polymorphic Client-Side WASM & JS Solvers
|
|
26
|
+
* **Polymorphic WebAssembly Solver**: Dynamically generates unique, randomized C++ compiled WebAssembly binary modules per session. Prevents static analysis, bot automation, and emulator tampering.
|
|
27
|
+
* **IndexedDB WASM Caching**: Transparently caches compiled WASM modules (`wasm-cache-db`) in the browser's IndexedDB, minimizing initialization overhead and execution lag on subsequent visits.
|
|
28
|
+
* **Advanced Obfuscation**: Uses multi-layered control flow flattening and string array obfuscation for client-side libraries.
|
|
29
|
+
|
|
30
|
+
### 2. 💱 Useful Proof-of-Work (uPoW) & PoSpace
|
|
31
|
+
* **Collaborative Useful PoW**: Instead of burning CPU cycles on arbitrary mathematical hash puzzles, suspicious clients solve complex optimization problems (e.g., *Traveling Salesperson*, *Portfolio Allocation*, *Facility Location*, *Fraud Detection Parameter Tuning*).
|
|
32
|
+
* **Proof-of-Space (PoSpace) Challenge**: Forces browser clients to allocate and verify access to massive, persistent storage chunks (e.g., 100MB) inside IndexedDB, multiplying the cost of multi-threaded headless automation.
|
|
33
|
+
* **Chained CPU/Memory Challenges**: Employs client-side resource exhaustion techniques (Chained SHA-256 target seeking & Memory Hard allocation vectors up to 128MB) that are validated in $O(1)$ on the server.
|
|
34
|
+
|
|
35
|
+
### 3. 🌐 Passive TLS, HTTP/2, and TCP/IP (p0f) Tracking
|
|
36
|
+
* **Native JA3/JA4 TLS Handshake Parsing**: Inspects raw TLS client hello bytes to extract and analyze cipher suite arrangements, extensions, and elliptic curve formats.
|
|
37
|
+
* **Passive TCP/IP Stack Fingerprinting**: Emulates `p0f` rules by analyzing raw TCP SYN packets (TTL, Window Size, MSS, WS, SACK) to classify client OS and detect raw network spoofing.
|
|
38
|
+
* **Multi-Language Handshake Parser**: Built-in support for event-driven PHP runtimes (Swoole, ReactPHP, Workerman), Node.js native sockets, and Python ASGI/WSGI contexts.
|
|
39
|
+
|
|
40
|
+
### 4. 🧠 Stateful Behavioral Entropy & Click Variance
|
|
41
|
+
* **Click Coordinate Variance**: Tracks exact click relative positions on DOM elements to compute spatial entropy, flagging bots clicking targets with robotic, mathematically perfect precision (zero variance).
|
|
42
|
+
* **Mobile Touch Move Dynamics**: Captures mobile-specific touchscreen signals, analyzing tactile contact area radius, variable pressure indices, and multi-touch capabilities.
|
|
43
|
+
* **Typing Keystroke Latency**: Measures real-time keystroke interval latencies to prevent automated text insertion.
|
|
44
|
+
|
|
45
|
+
### 5. 🔍 Cross-Layer & Analog Inconsistency Scoring
|
|
46
|
+
* **Layer Cross-Referencing**: Analyzes inconsistencies between User-Agent declarations, Client-Hints (`Sec-CH-UA`), TLS Handshake capabilities, and TCP stacks (e.g., claiming Windows NT on Chrome but negotiating TLS like curl/Safari on a Linux kernel).
|
|
47
|
+
* **Viewport Aspect ratio & Screen mismatches**: Detects virtualized viewports exceeding physical dimensions or fake hardware specifications.
|
|
48
|
+
|
|
49
|
+
### 6. 🦠 Honeypot Traps & Extensible WAF
|
|
50
|
+
* **Signed Trap URLs**: Injects visually hidden, signed trap URLs into the DOM. Attempts to crawl, probe, or scrape these URLs immediately condemn the device.
|
|
51
|
+
* **Recursive Injection Filters**: Inspects deeply nested payload structures (JSON/NoSQL/GraphQL) using a robust regular expression matrix to flag SQLi, XSS, XXE, SSTI, and JNDI (Log4Shell) vulnerabilities.
|
|
52
|
+
* **ModSecurity NodeJS Extensibility**: Allows plugging in native core rule sets or custom WAF rule compilers into the honeypot pipeline.
|
|
53
|
+
|
|
54
|
+
### 🧬 Progressive Threshold Auto-Tuning
|
|
55
|
+
* **Genetic Policy Optimizer**: Dynamically updates classification parameters using a multi-objective genetic algorithm on your actual sanitized traffic data.
|
|
56
|
+
* **Inertial Parameter Sliding**: Adjusts security thresholds slowly with an adaptive learning rate to prevent configuration spikes.
|
|
57
|
+
* **Sybil Protection**: Filters out traffic logs, ensuring individual compromised bot networks cannot pollute optimization datasets.
|
|
22
58
|
|
|
23
59
|
## Quick Start
|
|
24
60
|
|
|
@@ -62,9 +98,18 @@ We welcome community contributions! Please read our **[Contributing Guidelines](
|
|
|
62
98
|
Thanks to our contributors :
|
|
63
99
|
- [anonympins](https://github.com/anonympins)
|
|
64
100
|
|
|
65
|
-
##
|
|
101
|
+
## 💖 Sponsor This Project
|
|
102
|
+
|
|
103
|
+
If this security suite helps protect your business against botnets, automated scraping, credential stuffing, or Layer 7 DDoS attacks, please consider supporting its active development!
|
|
104
|
+
|
|
105
|
+
Sponsorship helps maintain the library, fund active updates, and keep the dynamic WebAssembly engine cutting-edge.
|
|
106
|
+
|
|
107
|
+
### 🌟 Featured Sponsors
|
|
108
|
+
|
|
109
|
+
<img src="https://s6.imgcdn.dev/YJTWv9.png" width="100" alt="YJTWv9.png" border="0" valign="middle">
|
|
110
|
+
|
|
111
|
+
[https://primals.net](https://primals.net) and sub-sites
|
|
66
112
|
|
|
67
|
-
- https://primals.net and sub-sites
|
|
68
113
|
|
|
69
114
|
## License
|
|
70
115
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anonympins/fingerprint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "vitest run --reporter=verbose",
|
|
12
|
+
"pub": "npm run build && npm login && npm publish --access public",
|
|
12
13
|
"build": "node src/js/build-client.js"
|
|
13
14
|
},
|
|
14
15
|
"exports": {
|
|
@@ -82,6 +82,56 @@ const ClientLibrary = {
|
|
|
82
82
|
*/
|
|
83
83
|
_hasher: (str, seed) => activeCyrb53(str, seed),
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Génère une preuve de connaissance à divulgation nulle (ZKP) de Schnorr pour l'empreinte de l'appareil.
|
|
87
|
+
* Rend le tout stable et compatible avec les vérifications JS, PHP et Python.
|
|
88
|
+
* @param {string} fingerprint - L'empreinte de l'appareil.
|
|
89
|
+
* @returns {Promise<string>} La preuve sous format "y:t:s" en hexadécimal.
|
|
90
|
+
*/
|
|
91
|
+
async generateZkpProof(fingerprint) {
|
|
92
|
+
const ZKP_P = 115792089237316195423570985008687907853269984665640564039457584007908834671663n;
|
|
93
|
+
const ZKP_G = 2n;
|
|
94
|
+
const cryptoObj = window.crypto || window.msCrypto;
|
|
95
|
+
|
|
96
|
+
const sha256Hex = async (str) => {
|
|
97
|
+
const encoder = new TextEncoder();
|
|
98
|
+
const data = encoder.encode(str);
|
|
99
|
+
const hashBuffer = await cryptoObj.subtle.digest('SHA-256', data);
|
|
100
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
101
|
+
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const modPow = (base, exponent, modulus) => {
|
|
105
|
+
if (modulus === 1n) return 0n;
|
|
106
|
+
let result = 1n;
|
|
107
|
+
base = base % modulus;
|
|
108
|
+
while (exponent > 0n) {
|
|
109
|
+
if (exponent % 2n === 1n) {
|
|
110
|
+
result = (result * base) % modulus;
|
|
111
|
+
}
|
|
112
|
+
exponent = exponent >> 1n;
|
|
113
|
+
base = (base * base) % modulus;
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const xHex = await sha256Hex(fingerprint);
|
|
119
|
+
const x = BigInt('0x' + xHex) % ZKP_P;
|
|
120
|
+
const y = modPow(ZKP_G, x, ZKP_P);
|
|
121
|
+
const randomBytes = new Uint8Array(32);
|
|
122
|
+
cryptoObj.getRandomValues(randomBytes);
|
|
123
|
+
let vHex = Array.from(randomBytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
124
|
+
let v = BigInt('0x' + vHex) % (ZKP_P - 1n);
|
|
125
|
+
if (v === 0n) v = 1n;
|
|
126
|
+
const t = modPow(ZKP_G, v, ZKP_P);
|
|
127
|
+
const cStr = ZKP_G.toString() + y.toString() + t.toString();
|
|
128
|
+
const cHex = await sha256Hex(cStr);
|
|
129
|
+
const c = BigInt('0x' + cHex) % ZKP_P;
|
|
130
|
+
const s = (v + c * x) % (ZKP_P - 1n);
|
|
131
|
+
|
|
132
|
+
return `${y.toString(16)}:${t.toString(16)}:${s.toString(16)}`;
|
|
133
|
+
},
|
|
134
|
+
|
|
85
135
|
/**
|
|
86
136
|
* Génère l'empreinte de l'appareil actuel.
|
|
87
137
|
*/
|
|
@@ -290,6 +340,91 @@ const ClientLibrary = {
|
|
|
290
340
|
document.addEventListener('touchend', handleTouch, { passive: true });
|
|
291
341
|
},
|
|
292
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Initialise l'espace Proof-of-Space persistant dans l'IndexedDB locale.
|
|
345
|
+
*/
|
|
346
|
+
async initializeSpace(seed, sizeMb) {
|
|
347
|
+
return new Promise((resolve, reject) => {
|
|
348
|
+
const request = indexedDB.open('pospace-db', 1);
|
|
349
|
+
request.onupgradeneeded = (e) => {
|
|
350
|
+
const db = e.target.result;
|
|
351
|
+
if (!db.objectStoreNames.contains('blocks')) {
|
|
352
|
+
db.createObjectStore('blocks');
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
request.onsuccess = async (e) => {
|
|
356
|
+
const db = e.target.result;
|
|
357
|
+
const tx = db.transaction('blocks', 'readwrite');
|
|
358
|
+
const store = tx.objectStore('blocks');
|
|
359
|
+
|
|
360
|
+
const maxBlocks = sizeMb * 1024;
|
|
361
|
+
const countReq = store.count();
|
|
362
|
+
countReq.onsuccess = async () => {
|
|
363
|
+
if (countReq.result < maxBlocks) {
|
|
364
|
+
for (let i = 0; i < maxBlocks; i++) {
|
|
365
|
+
const block = new Uint8Array(1024);
|
|
366
|
+
let h = 5381;
|
|
367
|
+
for (let j = 0; j < seed.length; j++) {
|
|
368
|
+
h = (h << 5) + h + seed.charCodeAt(j);
|
|
369
|
+
}
|
|
370
|
+
h = (h << 5) + h + i;
|
|
371
|
+
for (let k = 0; k < 1024; k++) {
|
|
372
|
+
h = Math.imul(h ^ k, 1597334677);
|
|
373
|
+
block[k] = h & 0xff;
|
|
374
|
+
}
|
|
375
|
+
store.put(block, i);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
resolve();
|
|
379
|
+
};
|
|
380
|
+
};
|
|
381
|
+
request.onerror = () => reject(new Error("Failed to open pospace database"));
|
|
382
|
+
});
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Lit un bloc spécifique de l'IndexedDB locale sous format hexadécimal.
|
|
387
|
+
*/
|
|
388
|
+
async readSpaceBlock(blockIdx) {
|
|
389
|
+
return new Promise((resolve, reject) => {
|
|
390
|
+
const request = indexedDB.open('pospace-db', 1);
|
|
391
|
+
request.onsuccess = (e) => {
|
|
392
|
+
const db = e.target.result;
|
|
393
|
+
const tx = db.transaction('blocks', 'readonly');
|
|
394
|
+
const store = tx.objectStore('blocks');
|
|
395
|
+
const getReq = store.get(blockIdx);
|
|
396
|
+
getReq.onsuccess = () => {
|
|
397
|
+
const block = getReq.result;
|
|
398
|
+
if (block) {
|
|
399
|
+
const hex = Array.from(block).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
400
|
+
resolve(hex);
|
|
401
|
+
} else {
|
|
402
|
+
reject(new Error("Block not found"));
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
getReq.onerror = () => reject(getReq.error);
|
|
406
|
+
};
|
|
407
|
+
request.onerror = () => reject(new Error("Failed to open pospace database"));
|
|
408
|
+
});
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Résout le Proof-of-Space en combinant optionnellement le bloc du pair.
|
|
413
|
+
*/
|
|
414
|
+
async solveSpaceChallenge(seed, queries, nonce, clientSecret, peerBlock = '') {
|
|
415
|
+
const blocks = [];
|
|
416
|
+
for (const idx of queries) {
|
|
417
|
+
const blockHex = await this.readSpaceBlock(idx);
|
|
418
|
+
blocks.push(blockHex);
|
|
419
|
+
}
|
|
420
|
+
let finalPayload = blocks.join('') + peerBlock + nonce + ":" + clientSecret;
|
|
421
|
+
const encoder = new TextEncoder();
|
|
422
|
+
const data = encoder.encode(finalPayload);
|
|
423
|
+
const hashBuffer = await window.crypto.subtle.digest('SHA-256', data);
|
|
424
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
425
|
+
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
426
|
+
},
|
|
427
|
+
|
|
293
428
|
/**
|
|
294
429
|
* Démarre le suivi des mouvements de la souris pour calculer l'entropie.
|
|
295
430
|
* À appeler une fois sur la page.
|
|
@@ -842,6 +977,10 @@ export const initializeWasm = ClientLibrary.initializeWasm.bind(ClientLibrary);
|
|
|
842
977
|
export const injectTrapLinks = ClientLibrary.injectTrapLinks.bind(ClientLibrary);
|
|
843
978
|
export const injectPhantomTraps = ClientLibrary.injectPhantomTraps.bind(ClientLibrary);
|
|
844
979
|
export const solveChallengeAndRetry = ClientLibrary.solveChallengeAndRetry.bind(ClientLibrary);
|
|
980
|
+
export const generateZkpProof = ClientLibrary.generateZkpProof.bind(ClientLibrary);
|
|
981
|
+
export const initializeSpace = ClientLibrary.initializeSpace.bind(ClientLibrary);
|
|
982
|
+
export const readSpaceBlock = ClientLibrary.readSpaceBlock.bind(ClientLibrary);
|
|
983
|
+
export const solveSpaceChallenge = ClientLibrary.solveSpaceChallenge.bind(ClientLibrary);
|
|
845
984
|
|
|
846
985
|
// Export the internal object for testing purposes
|
|
847
986
|
export default ClientLibrary;
|