auto-smart-security 1.1.0 → 1.1.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/dist/apply-security.js
CHANGED
|
@@ -40,11 +40,6 @@ function applySecurity(app, options) {
|
|
|
40
40
|
}
|
|
41
41
|
app.set('trust proxy', options.trustProxy);
|
|
42
42
|
}
|
|
43
|
-
/** ================= HELMET ================= */
|
|
44
|
-
app.use((0, helmet_1.default)({
|
|
45
|
-
crossOriginResourcePolicy: false, // 🔥
|
|
46
|
-
crossOriginOpenerPolicy: false, // disable API
|
|
47
|
-
}));
|
|
48
43
|
/** ================= BLACKLIST STORE ================= */
|
|
49
44
|
const blacklist = options.blacklist?.store ??
|
|
50
45
|
new memory_store_1.MemoryBlacklistStore(options.staticBlacklist, options.blacklistTTL);
|
|
@@ -57,63 +52,69 @@ function applySecurity(app, options) {
|
|
|
57
52
|
const path = url.split('?')[0].toLowerCase();
|
|
58
53
|
return STATIC_EXTENSIONS.some((ext) => path.endsWith(ext));
|
|
59
54
|
};
|
|
55
|
+
/** 3️⃣ Path whitelist */
|
|
56
|
+
const normalizePath = (url) => url.split('?')[0].replace(/^\/+/, '');
|
|
57
|
+
const isPathAllowed = (url, whitelist) => {
|
|
58
|
+
const path = normalizePath(url);
|
|
59
|
+
return whitelist.some((p) => path === p || path.includes(`${p}`));
|
|
60
|
+
};
|
|
61
|
+
function recordPathViolation(ip) {
|
|
62
|
+
const now = Date.now();
|
|
63
|
+
const entry = pathViolationMap.get(ip);
|
|
64
|
+
if (!entry || now - entry.ts > PATH_VIOLATION_TTL) {
|
|
65
|
+
pathViolationMap.set(ip, { count: 1, ts: now });
|
|
66
|
+
return false; // not block
|
|
67
|
+
}
|
|
68
|
+
entry.count++;
|
|
69
|
+
pathViolationMap.set(ip, entry);
|
|
70
|
+
return entry.count > PATH_VIOLATION_LIMIT; // block if limit exceeded
|
|
71
|
+
}
|
|
72
|
+
if (options.rateLimit) {
|
|
73
|
+
app.set('trust proxy', options.trustProxy);
|
|
74
|
+
// Lưu ý: createAdaptiveRateLimiter get IP/Trust
|
|
75
|
+
app.use((0, rate_limiter_1.createAdaptiveRateLimiter)(options.rateLimit, (req) => (0, utils_1.getClientIP)(req), (req) => (0, trust_engine_1.getTrustLevel)(req, (0, utils_1.getClientIP)(req), options.trust), (ip) => blacklist.block(ip)));
|
|
76
|
+
}
|
|
77
|
+
/** ================= HELMET ================= */
|
|
78
|
+
app.use((0, helmet_1.default)({
|
|
79
|
+
crossOriginResourcePolicy: false, // 🔥
|
|
80
|
+
crossOriginOpenerPolicy: false, // disable API
|
|
81
|
+
}));
|
|
60
82
|
/** ================= MAIN SECURITY ================= */
|
|
61
83
|
app.use(async (req, res, next) => {
|
|
62
84
|
const ip = (0, utils_1.getClientIP)(req);
|
|
63
85
|
const url = req.originalUrl;
|
|
64
|
-
|
|
65
|
-
/** ================= RATE LIMIT ================= */
|
|
66
|
-
if (options.rateLimit) {
|
|
67
|
-
app.use((0, rate_limiter_1.createAdaptiveRateLimiter)(options.rateLimit, (req) => (0, utils_1.getClientIP)(req), () => trustLevel, () => blacklist.block(ip)));
|
|
68
|
-
}
|
|
69
|
-
// pass OPTIONS requests
|
|
70
|
-
if (req.method === 'OPTIONS')
|
|
86
|
+
if (req.method === 'OPTIONS' || isStaticAsset(url))
|
|
71
87
|
return next();
|
|
88
|
+
const trustLevel = (0, trust_engine_1.getTrustLevel)(req, ip, options.trust);
|
|
89
|
+
const isWhitelisted = trustLevel >= 5;
|
|
90
|
+
const handleBlocking = async (reason) => {
|
|
91
|
+
options.onBlock?.({ ip, reason, url, ua: req.headers?.['user-agent'] });
|
|
92
|
+
if (isWhitelisted)
|
|
93
|
+
return false;
|
|
94
|
+
res.status(403).send(reason);
|
|
95
|
+
return true;
|
|
96
|
+
};
|
|
72
97
|
if (isStaticAsset(url))
|
|
73
98
|
return next();
|
|
74
99
|
/** 1️⃣ Blacklist */
|
|
75
100
|
if (await blacklist.isBlocked(ip)) {
|
|
76
|
-
|
|
101
|
+
if (await handleBlocking('blacklist'))
|
|
102
|
+
return;
|
|
77
103
|
}
|
|
78
104
|
/** 2️⃣ Bot detection */
|
|
79
105
|
if (botDetector?.detect(req, trustLevel)) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
url,
|
|
85
|
-
ua: req.headers?.['user-agent'],
|
|
86
|
-
});
|
|
87
|
-
return res.status(403).send('Bot detected');
|
|
88
|
-
}
|
|
89
|
-
/** 3️⃣ Path whitelist */
|
|
90
|
-
const normalizePath = (url) => url.split('?')[0].replace(/^\/+/, '');
|
|
91
|
-
const isPathAllowed = (url, whitelist) => {
|
|
92
|
-
const path = normalizePath(url);
|
|
93
|
-
return whitelist.some((p) => path === p || path.includes(`${p}`));
|
|
94
|
-
};
|
|
95
|
-
function recordPathViolation(ip) {
|
|
96
|
-
const now = Date.now();
|
|
97
|
-
const entry = pathViolationMap.get(ip);
|
|
98
|
-
if (!entry || now - entry.ts > PATH_VIOLATION_TTL) {
|
|
99
|
-
pathViolationMap.set(ip, { count: 1, ts: now });
|
|
100
|
-
return false; // not block
|
|
101
|
-
}
|
|
102
|
-
entry.count++;
|
|
103
|
-
pathViolationMap.set(ip, entry);
|
|
104
|
-
return entry.count > PATH_VIOLATION_LIMIT; // block if limit exceeded
|
|
106
|
+
if (!isWhitelisted)
|
|
107
|
+
await blacklist.block(ip, options.blacklistTTL);
|
|
108
|
+
if (await handleBlocking('bot-detected'))
|
|
109
|
+
return;
|
|
105
110
|
}
|
|
106
111
|
if (options.pathWhitelist?.length &&
|
|
107
112
|
!isPathAllowed(url, options.pathWhitelist)) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
reason: 'path-not-allowed',
|
|
114
|
-
url,
|
|
115
|
-
});
|
|
116
|
-
return res.status(403).send('Blocked path');
|
|
113
|
+
if (recordPathViolation(ip)) {
|
|
114
|
+
if (!isWhitelisted)
|
|
115
|
+
await blacklist.block(ip);
|
|
116
|
+
if (await handleBlocking('path-not-allowed'))
|
|
117
|
+
return;
|
|
117
118
|
}
|
|
118
119
|
}
|
|
119
120
|
next();
|
|
@@ -8,8 +8,10 @@ class MemoryBlacklistStore {
|
|
|
8
8
|
this.staticList = new Set(staticBlacklist);
|
|
9
9
|
}
|
|
10
10
|
isBlocked(ip) {
|
|
11
|
-
if (this.staticList.has(ip))
|
|
11
|
+
if (this.staticList.has(ip)) {
|
|
12
|
+
console.log(`[DEBUG] IP ${ip} detect block in MEMORY store`);
|
|
12
13
|
return true;
|
|
14
|
+
}
|
|
13
15
|
const exp = this.dynamic.get(ip);
|
|
14
16
|
if (!exp)
|
|
15
17
|
return false;
|