@liberstudio/cloudflare-list 3.0.0 → 3.0.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.
package/README.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Modulo NestJS per il rilevamento e blocco automatico di attacchi tramite Cloudflare IP List.
|
|
4
4
|
|
|
5
|
-
Ogni richiesta che produce un `404` viene considerata sospetta (tipicamente bot, scanner, enumeratori). L'IP viene risolto tramite ASN lookup per ottenere l'intero range di subnet e bloccarlo direttamente sulla lista Cloudflare WAF. Se il lookup fallisce, viene bloccato il singolo IP.
|
|
5
|
+
Ogni richiesta che produce un `404` su un indirizzo senza nessuna rotta viene considerata sospetta (tipicamente bot, scanner, enumeratori: `/wp-admin`, `/.env`). Il `404` restituito da una rotta esistente (es. `GET /artworks/:id` di una risorsa che non c'è) non viene bloccato. L'IP viene risolto tramite ASN lookup per ottenere l'intero range di subnet e bloccarlo direttamente sulla lista Cloudflare WAF. Se il lookup fallisce, viene bloccato il singolo IP.
|
|
6
6
|
|
|
7
7
|
## Come funziona
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
Request → 404 rilevato dal middleware
|
|
10
|
+
Request → 404 rilevato dal middleware (solo se nessuna rotta ha risposto)
|
|
11
11
|
└─ IP estratto (cf-connecting-ip / x-real-ip / x-forwarded-for)
|
|
12
12
|
└─ throttle 5s per IP
|
|
13
13
|
└─ log su file (se path non è silentPath)
|
|
@@ -42,7 +42,7 @@ let AttackLoggerMiddleware = AttackLoggerMiddleware_1 = class AttackLoggerMiddle
|
|
|
42
42
|
}
|
|
43
43
|
use(req, res, next) {
|
|
44
44
|
res.on("finish", () => {
|
|
45
|
-
if (res.statusCode === 404 && !this.isExcluded(req.url)) {
|
|
45
|
+
if (res.statusCode === 404 && !this.hasRealRoute(req) && !this.isExcluded(req.url)) {
|
|
46
46
|
this.handleSuspicious(req);
|
|
47
47
|
}
|
|
48
48
|
});
|
|
@@ -85,7 +85,7 @@ let AttackLoggerMiddleware = AttackLoggerMiddleware_1 = class AttackLoggerMiddle
|
|
|
85
85
|
this.logger.warn(`IP non valido: ${ip}`);
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
|
-
this.logger.warn(`Provenienza ${ip}: socket=${origin.remoteAddress} host=${origin.host} cf-ray=${origin.cfRay}`);
|
|
88
|
+
this.logger.warn(`Provenienza ${ip}: ${req.method} ${this.sanitize(req.originalUrl)} → 404, socket=${origin.remoteAddress} host=${origin.host} cf-ray=${origin.cfRay}`);
|
|
89
89
|
this.attSrv.blockIp(ip).catch((err) => {
|
|
90
90
|
const msg = err instanceof Error ? err.message : "Errore sconosciuto";
|
|
91
91
|
this.logger.error(`Aggiornamento Cloudflare fallito: ${msg}`);
|
|
@@ -110,6 +110,13 @@ let AttackLoggerMiddleware = AttackLoggerMiddleware_1 = class AttackLoggerMiddle
|
|
|
110
110
|
this.logger.log(`Cartella dei log creata: ${dir}`);
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
|
+
// Un 404 di una rotta esistente (es. risorsa non trovata) non è una scansione.
|
|
114
|
+
// Express lascia req.route solo se una rotta ha risposto; Nest 12 con prefisso globale
|
|
115
|
+
// gestisce gli indirizzi senza rotta con il catch-all '*path', che quindi non conta.
|
|
116
|
+
hasRealRoute(req) {
|
|
117
|
+
const path = req.route?.path;
|
|
118
|
+
return path !== undefined && path !== "*path";
|
|
119
|
+
}
|
|
113
120
|
isExcluded(url) {
|
|
114
121
|
const excluded = this.options.excludedPaths ?? [];
|
|
115
122
|
return excluded.some((p) => (p instanceof RegExp ? p.test(url) : url.startsWith(p)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liberstudio/cloudflare-list",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "Modulo NestJS per gestione IP List Cloudflare",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "npx tsc",
|
|
17
|
+
"test": "vitest run",
|
|
17
18
|
"prepublishOnly": "npm run build",
|
|
18
19
|
"version:bump": "npx tsx src/scripts/version-bump.ts",
|
|
19
20
|
"pub": "npm run build && npm publish --access public"
|
|
@@ -35,12 +36,14 @@
|
|
|
35
36
|
"@nestjs/axios": "^12.0.1",
|
|
36
37
|
"@nestjs/common": "^12.4.0",
|
|
37
38
|
"@nestjs/core": "^12.4.0",
|
|
39
|
+
"@nestjs/platform-express": "^12.4.2",
|
|
38
40
|
"@types/express": "^5.0.6",
|
|
39
|
-
"@types/node": "^
|
|
41
|
+
"@types/node": "^24.19.2",
|
|
40
42
|
"axios": "^1.21.0",
|
|
41
43
|
"rxjs": "^7.8.2",
|
|
42
44
|
"simple-git-hooks": "^2.13.1",
|
|
43
|
-
"typescript": "^5.0.0"
|
|
45
|
+
"typescript": "^5.0.0",
|
|
46
|
+
"vitest": "^5.1.0"
|
|
44
47
|
},
|
|
45
48
|
"allowScripts": {
|
|
46
49
|
"simple-git-hooks@2.13.1": true
|