@anonympins/fingerprint 0.0.1 → 0.0.2
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/README.md +136 -22
- package/fingerprint.js +502 -230
- package/library.js +0 -824
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# fingerprint
|
|
2
|
+

|
|
2
3
|

|
|
4
|
+

|
|
5
|
+

|
|
3
6
|

|
|
4
7
|
|
|
5
8
|
An HTTP(S) client mitigation and anti-bot protection library for Node.js/Express, based on digital fingerprinting and dynamic Proof-of-Work (PoW) challenges.
|
|
@@ -35,6 +38,7 @@ Once the challenge is solved, a clearance "ticket" is issued via a cookie, exemp
|
|
|
35
38
|
- **Pluggable Datastore**: Supports external datastores like Redis for state persistence and scalability across multiple server instances.
|
|
36
39
|
- **Express.js Middleware**: Easy integration into an Express application with `powMiddleware`.
|
|
37
40
|
- **Timing Attack Protection**: Uses `crypto.timingSafeEqual` for secure ticket validation.
|
|
41
|
+
- **Automatic Threshold Tuning**: (Optional) Includes a genetic algorithm-based optimizer (`startThresholdAutoTuning`) that analyzes real traffic to dynamically adjust suspicion thresholds (`low`, `medium`, `high`), improving bot detection accuracy and reducing false positives over time.
|
|
38
42
|
|
|
39
43
|
## Installation and Usage
|
|
40
44
|
|
|
@@ -69,17 +73,17 @@ app.use(cookieParser());
|
|
|
69
73
|
// Configuration of weights and thresholds for calculating the suspicion score.
|
|
70
74
|
// These values should be adjusted based on traffic and expected user behavior.
|
|
71
75
|
const securityConfig = {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
weights: {
|
|
77
|
+
historyScore: 0.3, // Penalizes IP rotation (proxy)
|
|
78
|
+
rotationScore: 0.5, // Penalizes rapid fingerprint changes (user-agent, etc.)
|
|
79
|
+
headerAnomalyScore: 0.1, // Penalizes abnormal headers (missing UA, etc.)
|
|
80
|
+
inconsistencyScore: 0.8 // Strongly penalizes inconsistency between the current and initial fingerprint (stolen cookie)
|
|
81
|
+
},
|
|
82
|
+
thresholds: {
|
|
83
|
+
low: 20, // Score from which a CPU challenge is issued
|
|
84
|
+
medium: 45, // Score for a Memory challenge
|
|
85
|
+
high: 75 // Score for a complex challenge (TSP/Captcha)
|
|
86
|
+
}
|
|
83
87
|
};
|
|
84
88
|
|
|
85
89
|
// In a real-world scenario, you would configure the middleware.
|
|
@@ -95,7 +99,7 @@ app.set('trust proxy', 1);
|
|
|
95
99
|
app.use(powMiddlewareInstance);
|
|
96
100
|
|
|
97
101
|
app.get('/', (req, res) => {
|
|
98
|
-
|
|
102
|
+
res.send('Welcome to the protected page!');
|
|
99
103
|
});
|
|
100
104
|
|
|
101
105
|
app.listen(3000, () => console.log('Server started on port 3000'));
|
|
@@ -129,19 +133,19 @@ import { RateLimiterMemory } from 'rate-limiter-flexible';
|
|
|
129
133
|
import { identifyRequest } from './fingerprint.js';
|
|
130
134
|
|
|
131
135
|
const rateLimiter = new RateLimiterMemory({
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
keyPrefix: 'rate_limit',
|
|
137
|
+
points: 10,
|
|
138
|
+
duration: 1,
|
|
135
139
|
});
|
|
136
140
|
|
|
137
141
|
app.use(async (req, res, next) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
try {
|
|
143
|
+
const key = await identifyRequest(req, res);
|
|
144
|
+
await rateLimiter.consume(key);
|
|
145
|
+
next();
|
|
146
|
+
} catch (err) {
|
|
147
|
+
res.status(429).send('Too Many Requests');
|
|
148
|
+
}
|
|
145
149
|
});
|
|
146
150
|
```
|
|
147
151
|
|
|
@@ -163,6 +167,116 @@ const fp = builder.toString(); // "os:hash1|ua:hash2"
|
|
|
163
167
|
#### `getDeviceFingerprint()`
|
|
164
168
|
*Client-side function only.* Generates a detailed browser fingerprint using APIs like Canvas, WebGL, etc.
|
|
165
169
|
|
|
170
|
+
## Advanced Features
|
|
171
|
+
|
|
172
|
+
### Architecture: `FingerprintEngine`
|
|
173
|
+
|
|
174
|
+
The core logic of the library is encapsulated within the `FingerprintEngine` class. The `powMiddleware` is essentially a lightweight wrapper that adapts this engine for use with Express.js.
|
|
175
|
+
|
|
176
|
+
The engine is responsible for:
|
|
177
|
+
1. Receiving a `requestContext` (IP, headers, cookies, etc.).
|
|
178
|
+
2. Calculating the suspicion score using the configured weights.
|
|
179
|
+
3. Making a decision: `next`, `challenge`, or `redirect` (after solving a challenge).
|
|
180
|
+
|
|
181
|
+
Although not exported for direct public use, understanding its role can be useful for advanced integrations or debugging.
|
|
182
|
+
|
|
183
|
+
### Manual Integration (outside Express.js)
|
|
184
|
+
|
|
185
|
+
While `powMiddleware` is convenient for Express, you can use the `FingerprintEngine` directly in any Node.js server environment (e.g., native `http`, Fastify, Koa). This gives you full control over the request/response cycle.
|
|
186
|
+
|
|
187
|
+
The engine is available via the internal exports: `import { __internal } from './fingerprint.js'`.
|
|
188
|
+
|
|
189
|
+
**Workflow:**
|
|
190
|
+
|
|
191
|
+
1. **Instantiate the Engine**: Create an instance with your `securityConfig`.
|
|
192
|
+
2. **Build the `requestContext`**: On each request, manually create a context object. It must include `clientIp`, `path`, `cookies`, `query`, `headers`, and mock `rawReq`/`rawRes` objects for cookie handling.
|
|
193
|
+
3. **Process the Request**: Call `engine.processRequest(requestContext)`.
|
|
194
|
+
4. **Handle the Decision**: The engine returns a decision object (`{ action: 'challenge' | 'redirect' | 'next', ... }`). You are responsible for implementing the corresponding HTTP response.
|
|
195
|
+
|
|
196
|
+
**Example with native Node.js `http` server:**
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
import http from 'http';
|
|
200
|
+
import { __internal } from './fingerprint.js'; // Adjust path
|
|
201
|
+
|
|
202
|
+
const { FingerprintEngine } = __internal;
|
|
203
|
+
const securityConfig = { /* ... your config ... */ };
|
|
204
|
+
const engine = new FingerprintEngine(securityConfig);
|
|
205
|
+
|
|
206
|
+
const server = http.createServer(async (req, res) => {
|
|
207
|
+
// 1. Manually build the context
|
|
208
|
+
const requestContext = {
|
|
209
|
+
clientIp: req.socket.remoteAddress,
|
|
210
|
+
path: req.url.split('?')[0],
|
|
211
|
+
cookies: {}, // Parse cookies from req.headers.cookie
|
|
212
|
+
query: {}, // Parse query string from req.url
|
|
213
|
+
headers: req.headers,
|
|
214
|
+
isStatic: /\.(js|css|png)$/.test(req.url),
|
|
215
|
+
rawReq: req, // Pass the raw request
|
|
216
|
+
rawRes: res, // Pass the raw response for cookie setting
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// 2. Process and get a decision
|
|
220
|
+
const decision = await engine.processRequest(requestContext);
|
|
221
|
+
|
|
222
|
+
// 3. Act on the decision
|
|
223
|
+
if (decision.action === 'challenge') {
|
|
224
|
+
res.writeHead(decision.status, { 'Content-Type': 'text/html' });
|
|
225
|
+
res.end(decision.body);
|
|
226
|
+
} else if (decision.action === 'redirect') {
|
|
227
|
+
// The engine sets the cookie directly on `res` via `rawRes`
|
|
228
|
+
res.writeHead(302, { 'Location': decision.path });
|
|
229
|
+
res.end();
|
|
230
|
+
} else { // 'next'
|
|
231
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
232
|
+
res.end('Welcome to the protected page!');
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
server.listen(3000, () => console.log('Server with manual fingerprint engine started on port 3000'));
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Automatic Threshold Tuning
|
|
240
|
+
|
|
241
|
+
Manually setting the `low`, `medium`, and `high` thresholds can be challenging. This library provides a powerful tool to automate this process based on real traffic data. It uses a genetic algorithm to find the optimal thresholds that maximize bot detection while minimizing the impact on legitimate users.
|
|
242
|
+
|
|
243
|
+
#### How to use it:
|
|
244
|
+
|
|
245
|
+
1. **Enable Logging**: The auto-tuner needs data. You must provide a `logger` function in your security configuration. This function will be called for significant events (`challenge_issued`, `challenge_solved`, etc.).
|
|
246
|
+
|
|
247
|
+
2. **Start the Tuner**: Call `startThresholdAutoTuning` with your live security configuration and the array where logs are stored.
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
import { powMiddleware, startThresholdAutoTuning } from './fingerprint.js';
|
|
251
|
+
|
|
252
|
+
// Array to store traffic analysis data. In a real application, this could be
|
|
253
|
+
// a more robust logging system.
|
|
254
|
+
const trafficData = [];
|
|
255
|
+
|
|
256
|
+
const securityConfig = {
|
|
257
|
+
weights: { /* ... your weights ... */ },
|
|
258
|
+
thresholds: {
|
|
259
|
+
low: 20, // Initial values, will be optimized
|
|
260
|
+
medium: 45,
|
|
261
|
+
high: 75
|
|
262
|
+
},
|
|
263
|
+
// The logger is required for auto-tuning
|
|
264
|
+
logger: (log) => trafficData.push(log)
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// Start the background optimization process.
|
|
268
|
+
// The `securityConfig.thresholds` object will be mutated with optimized values.
|
|
269
|
+
startThresholdAutoTuning({
|
|
270
|
+
securityConfig: securityConfig, // The config object to be updated
|
|
271
|
+
trafficData: trafficData, // The data source for the algorithm
|
|
272
|
+
interval: 1800000, // Optimization cycle every 30 minutes
|
|
273
|
+
minDataPoints: 200 // Minimum requests before starting optimization
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const powMiddlewareInstance = powMiddleware(securityConfig);
|
|
277
|
+
app.use(powMiddlewareInstance);
|
|
278
|
+
```
|
|
279
|
+
|
|
166
280
|
---
|
|
167
281
|
|
|
168
282
|
## License
|