xypriss 2.0.0 → 2.1.1
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 +171 -381
- package/dist/cjs/mods/security/src/algorithms/hash-algorithms.js +10 -0
- package/dist/cjs/mods/security/src/algorithms/hash-algorithms.js.map +1 -1
- package/dist/cjs/mods/security/src/components/cache/cacheSys.utils.js +10 -0
- package/dist/cjs/mods/security/src/components/cache/cacheSys.utils.js.map +1 -1
- package/dist/cjs/mods/security/src/components/cache/index.js +10 -2
- package/dist/cjs/mods/security/src/components/cache/index.js.map +1 -1
- package/dist/cjs/mods/security/src/components/fortified-function/index.js +9 -0
- package/dist/cjs/mods/security/src/components/fortified-function/index.js.map +1 -1
- package/dist/cjs/mods/security/src/components/fortified-function/security/security-handler.js +10 -0
- package/dist/cjs/mods/security/src/components/fortified-function/security/security-handler.js.map +1 -1
- package/dist/cjs/mods/security/src/core/crypto.js +14 -0
- package/dist/cjs/mods/security/src/core/crypto.js.map +1 -1
- package/dist/cjs/mods/security/src/index.js +10 -1
- package/dist/cjs/mods/security/src/index.js.map +1 -1
- package/dist/cjs/shared/logger/Logger.js +372 -29
- package/dist/cjs/shared/logger/Logger.js.map +1 -1
- package/dist/cjs/src/cluster/bun-cluster-manager.js +91 -1
- package/dist/cjs/src/cluster/bun-cluster-manager.js.map +1 -1
- package/dist/cjs/src/cluster/cluster-manager.js +15 -3
- package/dist/cjs/src/cluster/cluster-manager.js.map +1 -1
- package/dist/cjs/src/cluster/modules/AutoScaler.js +4 -4
- package/dist/cjs/src/cluster/modules/AutoScaler.js.map +1 -1
- package/dist/cjs/src/cluster/modules/CrossPlatformMemory.js +2 -2
- package/dist/cjs/src/cluster/modules/CrossPlatformMemory.js.map +1 -1
- package/dist/cjs/src/cluster/modules/EventLoopMonitor.js +270 -0
- package/dist/cjs/src/cluster/modules/EventLoopMonitor.js.map +1 -0
- package/dist/cjs/src/cluster/modules/GCStatsTracker.js +200 -0
- package/dist/cjs/src/cluster/modules/GCStatsTracker.js.map +1 -0
- package/dist/cjs/src/cluster/modules/HeapStatsCollector.js +111 -0
- package/dist/cjs/src/cluster/modules/HeapStatsCollector.js.map +1 -0
- package/dist/cjs/src/cluster/modules/NetworkTracker.js +162 -0
- package/dist/cjs/src/cluster/modules/NetworkTracker.js.map +1 -0
- package/dist/cjs/src/cluster/modules/ThroughputCalculator.js +186 -0
- package/dist/cjs/src/cluster/modules/ThroughputCalculator.js.map +1 -0
- package/dist/cjs/src/cluster/modules/WorkerManager.js +14 -15
- package/dist/cjs/src/cluster/modules/WorkerManager.js.map +1 -1
- package/dist/cjs/src/cluster/modules/{LoadBalancer.js → strategy/LoadBalancer.js} +1 -1
- package/dist/cjs/src/cluster/modules/strategy/LoadBalancer.js.map +1 -0
- package/dist/cjs/src/middleware/built-in/sqlInjection.js +335 -0
- package/dist/cjs/src/middleware/built-in/sqlInjection.js.map +1 -0
- package/dist/cjs/src/middleware/safe-json-middleware.js +1 -1
- package/dist/cjs/src/middleware/safe-json-middleware.js.map +1 -1
- package/dist/cjs/src/middleware/security-middleware.js +447 -332
- package/dist/cjs/src/middleware/security-middleware.js.map +1 -1
- package/dist/cjs/src/plugins/modules/index.js +9 -3
- package/dist/cjs/src/plugins/modules/index.js.map +1 -1
- package/dist/cjs/src/server/FastServer.js +41 -1
- package/dist/cjs/src/server/FastServer.js.map +1 -1
- package/dist/cjs/src/server/ServerFactory.js +62 -2
- package/dist/cjs/src/server/ServerFactory.js.map +1 -1
- package/dist/cjs/src/server/components/fastapi/ClusterManagerComponent.js +32 -6
- package/dist/cjs/src/server/components/fastapi/ClusterManagerComponent.js.map +1 -1
- package/dist/cjs/src/server/components/fastapi/WorkerPoolComponent.js +206 -0
- package/dist/cjs/src/server/components/fastapi/WorkerPoolComponent.js.map +1 -0
- package/dist/cjs/src/server/components/fastapi/console/ConsoleInterceptor.js +3 -28
- package/dist/cjs/src/server/components/fastapi/console/ConsoleInterceptor.js.map +1 -1
- package/dist/cjs/src/server/components/fastapi/modules/UFRP/WorkerPoolManager.js +265 -0
- package/dist/cjs/src/server/components/fastapi/modules/UFRP/WorkerPoolManager.js.map +1 -0
- package/dist/cjs/src/server/components/fastapi/modules/UFRP/workers/Logger.js +236 -0
- package/dist/cjs/src/server/components/fastapi/modules/UFRP/workers/cpu-tasks.js +294 -0
- package/dist/cjs/src/server/components/fastapi/modules/UFRP/workers/enhanced-cpu-worker.js +433 -0
- package/dist/cjs/src/server/components/fastapi/modules/UFRP/workers/io-worker.js +1615 -0
- package/dist/cjs/src/server/components/lifecycle/ServerLifecycleManager.js +143 -24
- package/dist/cjs/src/server/components/lifecycle/ServerLifecycleManager.js.map +1 -1
- package/dist/cjs/src/server/const/default.js +23 -9
- package/dist/cjs/src/server/const/default.js.map +1 -1
- package/dist/cjs/src/server/core/HttpServer.js +8 -8
- package/dist/cjs/src/server/core/HttpServer.js.map +1 -1
- package/dist/cjs/src/server/core/XyprissApp.js +284 -17
- package/dist/cjs/src/server/core/XyprissApp.js.map +1 -1
- package/dist/cjs/src/server/handlers/NotFoundHandler.js +1 -1
- package/dist/cjs/src/server/handlers/NotFoundHandler.js.map +1 -1
- package/dist/cjs/src/server/middleware/MiddlewareManager.js +57 -12
- package/dist/cjs/src/server/middleware/MiddlewareManager.js.map +1 -1
- package/dist/cjs/src/server/utils/forceClosePort.js +1 -1
- package/dist/cjs/src/server/utils/forceClosePort.js.map +1 -1
- package/dist/esm/mods/security/src/algorithms/hash-algorithms.js +10 -0
- package/dist/esm/mods/security/src/algorithms/hash-algorithms.js.map +1 -1
- package/dist/esm/mods/security/src/components/cache/cacheSys.utils.js +10 -0
- package/dist/esm/mods/security/src/components/cache/cacheSys.utils.js.map +1 -1
- package/dist/esm/mods/security/src/components/cache/index.js +10 -2
- package/dist/esm/mods/security/src/components/cache/index.js.map +1 -1
- package/dist/esm/mods/security/src/components/fortified-function/index.js +9 -0
- package/dist/esm/mods/security/src/components/fortified-function/index.js.map +1 -1
- package/dist/esm/mods/security/src/components/fortified-function/security/security-handler.js +10 -0
- package/dist/esm/mods/security/src/components/fortified-function/security/security-handler.js.map +1 -1
- package/dist/esm/mods/security/src/core/crypto.js +14 -0
- package/dist/esm/mods/security/src/core/crypto.js.map +1 -1
- package/dist/esm/mods/security/src/index.js +10 -1
- package/dist/esm/mods/security/src/index.js.map +1 -1
- package/dist/esm/shared/logger/Logger.js +372 -29
- package/dist/esm/shared/logger/Logger.js.map +1 -1
- package/dist/esm/src/cluster/bun-cluster-manager.js +91 -1
- package/dist/esm/src/cluster/bun-cluster-manager.js.map +1 -1
- package/dist/esm/src/cluster/cluster-manager.js +15 -3
- package/dist/esm/src/cluster/cluster-manager.js.map +1 -1
- package/dist/esm/src/cluster/modules/AutoScaler.js +4 -4
- package/dist/esm/src/cluster/modules/AutoScaler.js.map +1 -1
- package/dist/esm/src/cluster/modules/CrossPlatformMemory.js +2 -2
- package/dist/esm/src/cluster/modules/CrossPlatformMemory.js.map +1 -1
- package/dist/esm/src/cluster/modules/EventLoopMonitor.js +268 -0
- package/dist/esm/src/cluster/modules/EventLoopMonitor.js.map +1 -0
- package/dist/esm/src/cluster/modules/GCStatsTracker.js +198 -0
- package/dist/esm/src/cluster/modules/GCStatsTracker.js.map +1 -0
- package/dist/esm/src/cluster/modules/HeapStatsCollector.js +109 -0
- package/dist/esm/src/cluster/modules/HeapStatsCollector.js.map +1 -0
- package/dist/esm/src/cluster/modules/NetworkTracker.js +160 -0
- package/dist/esm/src/cluster/modules/NetworkTracker.js.map +1 -0
- package/dist/esm/src/cluster/modules/ThroughputCalculator.js +184 -0
- package/dist/esm/src/cluster/modules/ThroughputCalculator.js.map +1 -0
- package/dist/esm/src/cluster/modules/WorkerManager.js +14 -14
- package/dist/esm/src/cluster/modules/WorkerManager.js.map +1 -1
- package/dist/esm/src/cluster/modules/{LoadBalancer.js → strategy/LoadBalancer.js} +1 -1
- package/dist/esm/src/cluster/modules/strategy/LoadBalancer.js.map +1 -0
- package/dist/esm/src/middleware/built-in/sqlInjection.js +333 -0
- package/dist/esm/src/middleware/built-in/sqlInjection.js.map +1 -0
- package/dist/esm/src/middleware/safe-json-middleware.js +1 -1
- package/dist/esm/src/middleware/safe-json-middleware.js.map +1 -1
- package/dist/esm/src/middleware/security-middleware.js +447 -332
- package/dist/esm/src/middleware/security-middleware.js.map +1 -1
- package/dist/esm/src/plugins/modules/index.js +9 -3
- package/dist/esm/src/plugins/modules/index.js.map +1 -1
- package/dist/esm/src/server/FastServer.js +41 -1
- package/dist/esm/src/server/FastServer.js.map +1 -1
- package/dist/esm/src/server/ServerFactory.js +62 -2
- package/dist/esm/src/server/ServerFactory.js.map +1 -1
- package/dist/esm/src/server/components/fastapi/ClusterManagerComponent.js +32 -6
- package/dist/esm/src/server/components/fastapi/ClusterManagerComponent.js.map +1 -1
- package/dist/esm/src/server/components/fastapi/WorkerPoolComponent.js +204 -0
- package/dist/esm/src/server/components/fastapi/WorkerPoolComponent.js.map +1 -0
- package/dist/esm/src/server/components/fastapi/console/ConsoleInterceptor.js +2 -27
- package/dist/esm/src/server/components/fastapi/console/ConsoleInterceptor.js.map +1 -1
- package/dist/esm/src/server/components/fastapi/modules/UFRP/WorkerPoolManager.js +263 -0
- package/dist/esm/src/server/components/fastapi/modules/UFRP/WorkerPoolManager.js.map +1 -0
- package/dist/esm/src/server/components/fastapi/modules/UFRP/workers/Logger.js +236 -0
- package/dist/esm/src/server/components/fastapi/modules/UFRP/workers/cpu-tasks.js +294 -0
- package/dist/esm/src/server/components/fastapi/modules/UFRP/workers/enhanced-cpu-worker.js +433 -0
- package/dist/esm/src/server/components/fastapi/modules/UFRP/workers/io-worker.js +1615 -0
- package/dist/esm/src/server/components/lifecycle/ServerLifecycleManager.js +143 -24
- package/dist/esm/src/server/components/lifecycle/ServerLifecycleManager.js.map +1 -1
- package/dist/esm/src/server/const/default.js +23 -9
- package/dist/esm/src/server/const/default.js.map +1 -1
- package/dist/esm/src/server/core/HttpServer.js +8 -8
- package/dist/esm/src/server/core/HttpServer.js.map +1 -1
- package/dist/esm/src/server/core/XyprissApp.js +284 -17
- package/dist/esm/src/server/core/XyprissApp.js.map +1 -1
- package/dist/esm/src/server/handlers/NotFoundHandler.js +1 -1
- package/dist/esm/src/server/handlers/NotFoundHandler.js.map +1 -1
- package/dist/esm/src/server/middleware/MiddlewareManager.js +57 -12
- package/dist/esm/src/server/middleware/MiddlewareManager.js.map +1 -1
- package/dist/esm/src/server/utils/forceClosePort.js +1 -1
- package/dist/esm/src/server/utils/forceClosePort.js.map +1 -1
- package/dist/index.d.ts +675 -516
- package/package.json +9 -9
- package/dist/cjs/src/cluster/index.js +0 -361
- package/dist/cjs/src/cluster/index.js.map +0 -1
- package/dist/cjs/src/cluster/modules/ClusterFactory.js +0 -539
- package/dist/cjs/src/cluster/modules/ClusterFactory.js.map +0 -1
- package/dist/cjs/src/cluster/modules/LoadBalancer.js.map +0 -1
- package/dist/cjs/src/server/components/fastapi/UltraFastRequestProcessor.js +0 -668
- package/dist/cjs/src/server/components/fastapi/UltraFastRequestProcessor.js.map +0 -1
- package/dist/cjs/src/server/components/fastapi/middlewares/MiddlewareAPI.js +0 -347
- package/dist/cjs/src/server/components/fastapi/middlewares/MiddlewareAPI.js.map +0 -1
- package/dist/cjs/src/server/components/fastapi/middlewares/MiddlewareMethodsManager.js +0 -204
- package/dist/cjs/src/server/components/fastapi/middlewares/MiddlewareMethodsManager.js.map +0 -1
- package/dist/cjs/src/server/components/fastapi/middlewares/middlewareManager.js +0 -953
- package/dist/cjs/src/server/components/fastapi/middlewares/middlewareManager.js.map +0 -1
- package/dist/cjs/src/server/components/fastapi/modules/UFRP/WorkerPool.js +0 -56
- package/dist/cjs/src/server/components/fastapi/modules/UFRP/WorkerPool.js.map +0 -1
- package/dist/esm/src/cluster/index.js +0 -339
- package/dist/esm/src/cluster/index.js.map +0 -1
- package/dist/esm/src/cluster/modules/ClusterFactory.js +0 -511
- package/dist/esm/src/cluster/modules/ClusterFactory.js.map +0 -1
- package/dist/esm/src/cluster/modules/LoadBalancer.js.map +0 -1
- package/dist/esm/src/server/components/fastapi/UltraFastRequestProcessor.js +0 -647
- package/dist/esm/src/server/components/fastapi/UltraFastRequestProcessor.js.map +0 -1
- package/dist/esm/src/server/components/fastapi/middlewares/MiddlewareAPI.js +0 -345
- package/dist/esm/src/server/components/fastapi/middlewares/MiddlewareAPI.js.map +0 -1
- package/dist/esm/src/server/components/fastapi/middlewares/MiddlewareMethodsManager.js +0 -202
- package/dist/esm/src/server/components/fastapi/middlewares/MiddlewareMethodsManager.js.map +0 -1
- package/dist/esm/src/server/components/fastapi/middlewares/middlewareManager.js +0 -951
- package/dist/esm/src/server/components/fastapi/middlewares/middlewareManager.js.map +0 -1
- package/dist/esm/src/server/components/fastapi/modules/UFRP/WorkerPool.js +0 -54
- package/dist/esm/src/server/components/fastapi/modules/UFRP/WorkerPool.js.map +0 -1
|
@@ -1,411 +1,526 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import '
|
|
4
|
-
import '
|
|
5
|
-
import '
|
|
6
|
-
import '
|
|
7
|
-
import '
|
|
8
|
-
import '
|
|
9
|
-
import '
|
|
10
|
-
import '
|
|
11
|
-
import '
|
|
12
|
-
import '../../mods/security/src/utils/memory/index.js';
|
|
13
|
-
import '../../mods/security/src/types.js';
|
|
14
|
-
import '../../mods/security/src/types/secure-memory.js';
|
|
15
|
-
import '../../mods/security/src/components/secure-string/advanced/entropy-analyzer.js';
|
|
16
|
-
import '../../mods/security/src/components/secure-string/advanced/quantum-safe.js';
|
|
17
|
-
import '../../mods/security/src/components/secure-string/advanced/performance-monitor.js';
|
|
18
|
-
import 'nehoid';
|
|
1
|
+
import helmet from 'helmet';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import rateLimit from 'express-rate-limit';
|
|
4
|
+
import { doubleCsrf } from 'csrf-csrf';
|
|
5
|
+
import mongoSanitize from 'express-mongo-sanitize';
|
|
6
|
+
import xss from 'xss';
|
|
7
|
+
import hpp from 'hpp';
|
|
8
|
+
import compression from 'compression';
|
|
9
|
+
import { XyPrissSecurity } from 'xypriss-security';
|
|
10
|
+
import SQLInjectionDetector from './built-in/sqlInjection.js';
|
|
11
|
+
import { Logger } from '../../shared/logger/Logger.js';
|
|
19
12
|
|
|
20
13
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
14
|
+
* XyPriss Security Middleware
|
|
15
|
+
* Comprehensive security middleware using proven external libraries
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Security middleware class implementing comprehensive protection
|
|
19
|
+
* Implements SecurityConfig interface to ensure type safety
|
|
23
20
|
*/
|
|
24
21
|
class SecurityMiddleware {
|
|
25
|
-
constructor(config = {}) {
|
|
26
|
-
|
|
27
|
-
this.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
constructor(config = {}, logger) {
|
|
23
|
+
// Initialize logger (create default if not provided)
|
|
24
|
+
this.logger =
|
|
25
|
+
logger ||
|
|
26
|
+
new Logger({
|
|
27
|
+
enabled: true,
|
|
28
|
+
level: "debug",
|
|
29
|
+
components: { security: true },
|
|
30
|
+
types: { debug: true },
|
|
31
|
+
});
|
|
32
|
+
// Set defaults and merge with provided config
|
|
33
|
+
this.level = config.level || "enhanced";
|
|
34
|
+
this.csrf = config.csrf !== false;
|
|
35
|
+
this.helmet = config.helmet !== false;
|
|
36
|
+
this.xss = config.xss !== false;
|
|
37
|
+
this.sqlInjection = config.sqlInjection !== false;
|
|
38
|
+
this.bruteForce = config.bruteForce !== false;
|
|
39
|
+
this.encryption = {
|
|
40
|
+
algorithm: "AES-256-GCM",
|
|
41
|
+
keySize: 32,
|
|
42
|
+
...config.encryption,
|
|
43
|
+
};
|
|
44
|
+
this.authentication = {
|
|
45
|
+
jwt: {
|
|
46
|
+
secret: config.authentication?.jwt?.secret ||
|
|
47
|
+
XyPrissSecurity.generateSecureToken({
|
|
41
48
|
length: 32,
|
|
42
49
|
entropy: "high",
|
|
43
50
|
}),
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
expiresIn: config.authentication?.jwt?.expiresIn || "1h",
|
|
52
|
+
algorithm: config.authentication?.jwt?.algorithm || "HS256",
|
|
53
|
+
},
|
|
54
|
+
session: {
|
|
55
|
+
secret: config.authentication?.session?.secret ||
|
|
56
|
+
XyPrissSecurity.generateSecureToken({
|
|
49
57
|
length: 32,
|
|
50
58
|
entropy: "high",
|
|
51
59
|
}),
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
name: config.authentication?.session?.name ||
|
|
61
|
+
"nehonix.XyPriss.sid",
|
|
62
|
+
cookie: {
|
|
63
|
+
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
64
|
+
secure: true,
|
|
65
|
+
httpOnly: true,
|
|
66
|
+
sameSite: "strict",
|
|
67
|
+
...config.authentication?.session?.cookie,
|
|
59
68
|
},
|
|
60
69
|
},
|
|
61
|
-
...config,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Get the main security middleware
|
|
66
|
-
*/
|
|
67
|
-
getMiddleware() {
|
|
68
|
-
return (req, res, next) => {
|
|
69
|
-
// Apply security measures based on level
|
|
70
|
-
this.applySecurityHeaders(req, res);
|
|
71
|
-
this.checkBruteForce(req, res, next);
|
|
70
|
+
...config.authentication,
|
|
72
71
|
};
|
|
72
|
+
// Initialize security detectors
|
|
73
|
+
this.sqlInjectionDetector = new SQLInjectionDetector({
|
|
74
|
+
strictMode: false,
|
|
75
|
+
contextualAnalysis: true,
|
|
76
|
+
logAttempts: true,
|
|
77
|
+
falsePositiveThreshold: 0.6,
|
|
78
|
+
});
|
|
79
|
+
// Initialize all middleware instances
|
|
80
|
+
this.initializeMiddleware();
|
|
73
81
|
}
|
|
74
82
|
/**
|
|
75
|
-
*
|
|
83
|
+
* Initialize all security middleware instances using external libraries
|
|
76
84
|
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
initializeMiddleware() {
|
|
86
|
+
// Helmet for security headers
|
|
87
|
+
if (this.helmet) {
|
|
88
|
+
this.helmetMiddleware = helmet({
|
|
89
|
+
contentSecurityPolicy: this.level === "maximum"
|
|
90
|
+
? {
|
|
91
|
+
directives: {
|
|
92
|
+
defaultSrc: ["'self'"],
|
|
93
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
94
|
+
scriptSrc: ["'self'"],
|
|
95
|
+
imgSrc: ["'self'", "data:", "https:"],
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
: false,
|
|
99
|
+
hsts: this.level !== "basic",
|
|
100
|
+
crossOriginEmbedderPolicy: this.level === "maximum",
|
|
88
101
|
});
|
|
89
102
|
}
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const maxAttempts = 10;
|
|
118
|
-
const windowMs = 15 * 60 * 1000; // 15 minutes
|
|
119
|
-
const blockDuration = 60 * 60 * 1000; // 1 hour
|
|
120
|
-
let record = this.bruteForceMap.get(ip);
|
|
121
|
-
if (!record) {
|
|
122
|
-
record = { attempts: 0, lastAttempt: now };
|
|
123
|
-
this.bruteForceMap.set(ip, record);
|
|
103
|
+
// CORS middleware
|
|
104
|
+
this.corsMiddleware = cors({
|
|
105
|
+
origin: this.level === "maximum" ? false : true,
|
|
106
|
+
credentials: true,
|
|
107
|
+
optionsSuccessStatus: 200,
|
|
108
|
+
});
|
|
109
|
+
// Rate limiting for brute force protection
|
|
110
|
+
if (this.bruteForce) {
|
|
111
|
+
const maxRequests = this.level === "maximum"
|
|
112
|
+
? 50
|
|
113
|
+
: this.level === "enhanced"
|
|
114
|
+
? 100
|
|
115
|
+
: 200;
|
|
116
|
+
this.rateLimitMiddleware = rateLimit({
|
|
117
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
118
|
+
max: maxRequests,
|
|
119
|
+
message: {
|
|
120
|
+
error: "Too many requests from this IP, please try again later.",
|
|
121
|
+
retryAfter: "15 minutes",
|
|
122
|
+
},
|
|
123
|
+
standardHeaders: true,
|
|
124
|
+
legacyHeaders: false,
|
|
125
|
+
skip: (req) => {
|
|
126
|
+
// Skip rate limiting for health checks
|
|
127
|
+
return req.path === "/health" || req.path === "/ping";
|
|
128
|
+
},
|
|
129
|
+
});
|
|
124
130
|
}
|
|
125
|
-
//
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
131
|
+
// CSRF protection using csrf-csrf library
|
|
132
|
+
if (this.csrf) {
|
|
133
|
+
const { doubleCsrfProtection } = doubleCsrf({
|
|
134
|
+
getSecret: () => this.authentication.session?.secret || "default-secret",
|
|
135
|
+
getSessionIdentifier: (req) => req.sessionID || req.ip || "anonymous",
|
|
136
|
+
cookieName: "__Host-csrf-token",
|
|
137
|
+
cookieOptions: {
|
|
138
|
+
httpOnly: true,
|
|
139
|
+
sameSite: "strict",
|
|
140
|
+
secure: process.env.NODE_ENV === "production",
|
|
141
|
+
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
142
|
+
},
|
|
143
|
+
size: 64,
|
|
144
|
+
ignoredMethods: ["GET", "HEAD", "OPTIONS"],
|
|
130
145
|
});
|
|
146
|
+
// Create a wrapper that ensures cookies exist
|
|
147
|
+
this.csrfMiddleware = (req, res, next) => {
|
|
148
|
+
// Ensure cookies object exists for Express compatibility
|
|
149
|
+
if (!req.cookies) {
|
|
150
|
+
req.cookies = {};
|
|
151
|
+
}
|
|
152
|
+
// Call the original CSRF middleware
|
|
153
|
+
doubleCsrfProtection(req, res, next);
|
|
154
|
+
};
|
|
131
155
|
}
|
|
132
|
-
//
|
|
133
|
-
if (
|
|
134
|
-
|
|
156
|
+
// MongoDB injection protection
|
|
157
|
+
if (this.sqlInjection) {
|
|
158
|
+
const originalMongoSanitize = mongoSanitize({
|
|
159
|
+
replaceWith: "_",
|
|
160
|
+
onSanitize: ({ req, key }) => {
|
|
161
|
+
console.warn(`Sanitized key ${key} in request from ${req.ip}`);
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
// Create a wrapper that handles readonly properties
|
|
165
|
+
this.mongoSanitizeMiddleware = (req, res, next) => {
|
|
166
|
+
// Make request properties writable before sanitization
|
|
167
|
+
this.makeRequestPropertiesWritable(req);
|
|
168
|
+
// Call the original middleware
|
|
169
|
+
originalMongoSanitize(req, res, next);
|
|
170
|
+
};
|
|
135
171
|
}
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
172
|
+
// HTTP Parameter Pollution protection
|
|
173
|
+
const originalHpp = hpp({
|
|
174
|
+
whitelist: ["tags", "categories"], // Allow arrays for specific parameters
|
|
175
|
+
});
|
|
176
|
+
// Create a wrapper that handles readonly properties
|
|
177
|
+
this.hppMiddleware = (req, res, next) => {
|
|
178
|
+
// Make request properties writable before processing
|
|
179
|
+
this.makeRequestPropertiesWritable(req);
|
|
180
|
+
// Call the original middleware
|
|
181
|
+
originalHpp(req, res, next);
|
|
182
|
+
};
|
|
183
|
+
// Compression middleware
|
|
184
|
+
this.compressionMiddleware = compression({
|
|
185
|
+
filter: (req, res) => {
|
|
186
|
+
if (req.headers["x-no-compression"]) {
|
|
187
|
+
return false;
|
|
144
188
|
}
|
|
145
|
-
|
|
189
|
+
return compression.filter(req, res);
|
|
190
|
+
},
|
|
191
|
+
level: 6,
|
|
192
|
+
threshold: 1024,
|
|
146
193
|
});
|
|
147
|
-
next();
|
|
148
194
|
}
|
|
149
195
|
/**
|
|
150
|
-
*
|
|
196
|
+
* Get the main security middleware stack
|
|
197
|
+
* Returns a single middleware function that applies all security measures
|
|
151
198
|
*/
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
// Check for excessive hex encoding
|
|
159
|
-
const hexCount = (input.match(/\\x[0-9a-f]{2}/gi) || []).length;
|
|
160
|
-
if (hexCount > 3) {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
// Check for suspicious character sequences
|
|
164
|
-
const suspiciousPatterns = [
|
|
165
|
-
/(\+|\s)(and|or)(\+|\s)/gi,
|
|
166
|
-
/[0-9]+\s*[=<>]\s*[0-9]+/gi,
|
|
167
|
-
/(char|ascii)\s*\(\s*[0-9]+/gi,
|
|
168
|
-
/concat\s*\(/gi,
|
|
169
|
-
];
|
|
170
|
-
return suspiciousPatterns.some((pattern) => pattern.test(input));
|
|
199
|
+
getMiddleware() {
|
|
200
|
+
return (req, res, next) => {
|
|
201
|
+
this.applySecurityStack(req, res, next);
|
|
202
|
+
};
|
|
171
203
|
}
|
|
172
204
|
/**
|
|
173
|
-
*
|
|
205
|
+
* Apply all security middleware in the correct order
|
|
174
206
|
*/
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
207
|
+
applySecurityStack(req, res, next) {
|
|
208
|
+
this.logger.debug("security", "Starting security middleware stack");
|
|
209
|
+
const middlewareStack = [];
|
|
210
|
+
// 1. Compression (should be first)
|
|
211
|
+
this.logger.debug("security", "Adding compression middleware");
|
|
212
|
+
middlewareStack.push(this.compressionMiddleware);
|
|
213
|
+
// 2. Security headers (Helmet)
|
|
214
|
+
if (this.helmet && this.helmetMiddleware) {
|
|
215
|
+
this.logger.debug("security", "Adding helmet middleware");
|
|
216
|
+
middlewareStack.push(this.helmetMiddleware);
|
|
217
|
+
}
|
|
218
|
+
// 3. CORS
|
|
219
|
+
this.logger.debug("security", "Adding CORS middleware");
|
|
220
|
+
middlewareStack.push(this.corsMiddleware);
|
|
221
|
+
// 4. Rate limiting
|
|
222
|
+
if (this.bruteForce && this.rateLimitMiddleware) {
|
|
223
|
+
this.logger.debug("security", "Adding rate limit middleware");
|
|
224
|
+
middlewareStack.push(this.rateLimitMiddleware);
|
|
225
|
+
}
|
|
226
|
+
// 5. HTTP Parameter Pollution protection
|
|
227
|
+
this.logger.debug("security", "Adding HPP middleware");
|
|
228
|
+
middlewareStack.push(this.hppMiddleware);
|
|
229
|
+
// 6. MongoDB sanitization
|
|
230
|
+
if (this.sqlInjection && this.mongoSanitizeMiddleware) {
|
|
231
|
+
this.logger.debug("security", "Adding mongo sanitize middleware");
|
|
232
|
+
middlewareStack.push(this.mongoSanitizeMiddleware);
|
|
233
|
+
}
|
|
234
|
+
// 7. XSS protection (custom implementation)
|
|
235
|
+
if (this.xss) {
|
|
236
|
+
this.logger.debug("security", "Adding XSS protection middleware");
|
|
237
|
+
middlewareStack.push(this.xssProtection.bind(this));
|
|
238
|
+
}
|
|
239
|
+
// 8. CSRF protection (should be after body parsing)
|
|
240
|
+
if (this.csrf && this.csrfMiddleware) {
|
|
241
|
+
this.logger.debug("security", "Adding CSRF middleware");
|
|
242
|
+
middlewareStack.push(this.csrfMiddleware);
|
|
243
|
+
}
|
|
244
|
+
this.logger.debug("security", `Total middleware in stack: ${middlewareStack.length}`);
|
|
245
|
+
// Execute middleware stack
|
|
246
|
+
this.executeMiddlewareStack(middlewareStack, req, res, next);
|
|
182
247
|
}
|
|
183
248
|
/**
|
|
184
|
-
*
|
|
249
|
+
* Execute middleware stack sequentially with proper async handling
|
|
185
250
|
*/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
251
|
+
executeMiddlewareStack(stack, req, res, finalNext) {
|
|
252
|
+
let index = 0;
|
|
253
|
+
let nextCalled = false;
|
|
254
|
+
this.logger.debug("security", `Executing middleware stack with ${stack.length} middleware`);
|
|
255
|
+
const next = (error) => {
|
|
256
|
+
if (nextCalled) {
|
|
257
|
+
this.logger.debug("security", "next() already called, ignoring duplicate call");
|
|
258
|
+
return;
|
|
190
259
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
next();
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* SQL Injection protection middleware
|
|
200
|
-
*/
|
|
201
|
-
sqlInjectionProtection() {
|
|
202
|
-
return (req, res, next) => {
|
|
203
|
-
if (!this.config.sqlInjection) {
|
|
204
|
-
return next();
|
|
260
|
+
if (error) {
|
|
261
|
+
nextCalled = true;
|
|
262
|
+
this.logger.debug("security", `Error in middleware at index ${index - 1}:`, error);
|
|
263
|
+
return finalNext(error);
|
|
205
264
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
];
|
|
225
|
-
const validateSQLInput = (obj, path = "") => {
|
|
226
|
-
if (typeof obj === "string") {
|
|
227
|
-
// Use XyPrissJS pattern matching for enhanced detection
|
|
228
|
-
const normalizedInput = obj
|
|
229
|
-
.toLowerCase()
|
|
230
|
-
.replace(/\s+/g, " ")
|
|
231
|
-
.trim();
|
|
232
|
-
// Check against SQL injection patterns
|
|
233
|
-
for (const pattern of sqlPatterns) {
|
|
234
|
-
if (pattern.test(normalizedInput)) {
|
|
235
|
-
console.warn(` SQL injection pattern detected in ${path}: ${pattern.source}`);
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
// Additional entropy-based detection for obfuscated attacks
|
|
240
|
-
if (this.detectObfuscatedSQLInjection(normalizedInput)) {
|
|
241
|
-
console.warn(` Obfuscated SQL injection detected in ${path}`);
|
|
242
|
-
return true;
|
|
265
|
+
if (index >= stack.length) {
|
|
266
|
+
nextCalled = true;
|
|
267
|
+
this.logger.debug("security", "All middleware completed, calling final next");
|
|
268
|
+
return finalNext();
|
|
269
|
+
}
|
|
270
|
+
const currentIndex = index;
|
|
271
|
+
this.logger.debug("security", `Executing middleware ${currentIndex + 1}/${stack.length}`);
|
|
272
|
+
const middleware = stack[index++];
|
|
273
|
+
try {
|
|
274
|
+
// Set a timeout to detect if middleware doesn't call next()
|
|
275
|
+
let timeoutId = null;
|
|
276
|
+
let middlewareCompleted = false;
|
|
277
|
+
const middlewareNext = (err) => {
|
|
278
|
+
if (middlewareCompleted)
|
|
279
|
+
return;
|
|
280
|
+
middlewareCompleted = true;
|
|
281
|
+
if (timeoutId) {
|
|
282
|
+
clearTimeout(timeoutId);
|
|
243
283
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
284
|
+
this.logger.debug("security", `Middleware ${currentIndex + 1} completed`);
|
|
285
|
+
next(err);
|
|
286
|
+
};
|
|
287
|
+
// Set timeout to detect hanging middleware
|
|
288
|
+
timeoutId = setTimeout(() => {
|
|
289
|
+
if (!middlewareCompleted) {
|
|
290
|
+
this.logger.debug("security", `Middleware ${currentIndex + 1} timed out, continuing anyway`);
|
|
291
|
+
middlewareCompleted = true;
|
|
292
|
+
next();
|
|
251
293
|
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return res.status(400).json({
|
|
260
|
-
error: "Invalid input detected",
|
|
261
|
-
});
|
|
294
|
+
}, 100); // 100ms timeout
|
|
295
|
+
// Execute the middleware
|
|
296
|
+
middleware(req, res, middlewareNext);
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
this.logger.debug("security", `Exception in middleware at index ${currentIndex}:`, error);
|
|
300
|
+
finalNext(error);
|
|
262
301
|
}
|
|
263
|
-
next();
|
|
264
302
|
};
|
|
303
|
+
// Start the middleware chain
|
|
304
|
+
this.logger.debug("security", "Starting middleware chain");
|
|
305
|
+
next();
|
|
265
306
|
}
|
|
266
307
|
/**
|
|
267
|
-
*
|
|
308
|
+
* Custom XSS protection middleware
|
|
268
309
|
*/
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
310
|
+
xssProtection(req, res, next) {
|
|
311
|
+
let maliciousContentDetected = false;
|
|
312
|
+
const detectedThreats = [];
|
|
313
|
+
// Check and sanitize request body
|
|
314
|
+
if (req.body && typeof req.body === "object") {
|
|
315
|
+
const { sanitized, threats } = this.sanitizeObjectWithDetection(req.body);
|
|
316
|
+
if (threats.length > 0) {
|
|
317
|
+
maliciousContentDetected = true;
|
|
318
|
+
detectedThreats.push(...threats.map((t) => `body.${t}`));
|
|
273
319
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
return next();
|
|
320
|
+
try {
|
|
321
|
+
req.body = sanitized;
|
|
277
322
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
req
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
!XyPrissSecurity.constantTimeEqual(token, sessionToken)) {
|
|
285
|
-
return res.status(403).json({
|
|
286
|
-
error: "CSRF token validation failed",
|
|
323
|
+
catch (error) {
|
|
324
|
+
// Handle readonly property - create new object
|
|
325
|
+
Object.defineProperty(req, "body", {
|
|
326
|
+
value: sanitized,
|
|
327
|
+
writable: true,
|
|
328
|
+
configurable: true,
|
|
287
329
|
});
|
|
288
330
|
}
|
|
289
|
-
|
|
290
|
-
|
|
331
|
+
}
|
|
332
|
+
// Check and sanitize query parameters
|
|
333
|
+
if (req.query && typeof req.query === "object") {
|
|
334
|
+
const { sanitized, threats } = this.sanitizeObjectWithDetection(req.query);
|
|
335
|
+
if (threats.length > 0) {
|
|
336
|
+
maliciousContentDetected = true;
|
|
337
|
+
detectedThreats.push(...threats.map((t) => `query.${t}`));
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
req.query = sanitized;
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
// Handle readonly property - create new object
|
|
344
|
+
Object.defineProperty(req, "query", {
|
|
345
|
+
value: sanitized,
|
|
346
|
+
writable: true,
|
|
347
|
+
configurable: true,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Check and sanitize URL parameters
|
|
352
|
+
if (req.params && typeof req.params === "object") {
|
|
353
|
+
const { sanitized, threats } = this.sanitizeObjectWithDetection(req.params);
|
|
354
|
+
if (threats.length > 0) {
|
|
355
|
+
maliciousContentDetected = true;
|
|
356
|
+
detectedThreats.push(...threats.map((t) => `params.${t}`));
|
|
357
|
+
}
|
|
358
|
+
try {
|
|
359
|
+
req.params = sanitized;
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
// Handle readonly property - create new object
|
|
363
|
+
Object.defineProperty(req, "params", {
|
|
364
|
+
value: sanitized,
|
|
365
|
+
writable: true,
|
|
366
|
+
configurable: true,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// Block request if malicious content was detected
|
|
371
|
+
if (maliciousContentDetected) {
|
|
372
|
+
this.logger.warn("security", `XSS attack blocked from ${req.ip}. Threats detected: ${detectedThreats.join(", ")}`);
|
|
373
|
+
res.status(400).json({
|
|
374
|
+
error: "Malicious content detected",
|
|
375
|
+
message: "Request blocked due to potential XSS attack",
|
|
376
|
+
threats: detectedThreats,
|
|
377
|
+
timestamp: new Date().toISOString(),
|
|
378
|
+
});
|
|
379
|
+
return; // Don't call next() - block the request
|
|
380
|
+
}
|
|
381
|
+
next();
|
|
291
382
|
}
|
|
292
383
|
/**
|
|
293
|
-
*
|
|
384
|
+
* Make request properties writable to avoid readonly property errors
|
|
294
385
|
*/
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
if (
|
|
299
|
-
return next();
|
|
300
|
-
}
|
|
301
|
-
// Check if request is encrypted
|
|
302
|
-
const encryptedHeader = req.headers["x-encrypted-request"];
|
|
303
|
-
if (encryptedHeader && req.body) {
|
|
386
|
+
makeRequestPropertiesWritable(req) {
|
|
387
|
+
const properties = ["body", "params", "headers", "query"];
|
|
388
|
+
properties.forEach((prop) => {
|
|
389
|
+
if (req[prop] !== undefined) {
|
|
304
390
|
try {
|
|
305
|
-
//
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
secureObj.setEncryptionKey(self.config.authentication?.jwt?.secret || "default-key");
|
|
309
|
-
const decryptedData = secureObj.toObject();
|
|
310
|
-
req.body = JSON.parse(decryptedData.data);
|
|
391
|
+
// Test if property is writable
|
|
392
|
+
const original = req[prop];
|
|
393
|
+
req[prop] = original;
|
|
311
394
|
}
|
|
312
395
|
catch (error) {
|
|
313
|
-
|
|
314
|
-
|
|
396
|
+
// Property is readonly, make it writable
|
|
397
|
+
const value = req[prop];
|
|
398
|
+
Object.defineProperty(req, prop, {
|
|
399
|
+
value: value,
|
|
400
|
+
writable: true,
|
|
401
|
+
configurable: true,
|
|
402
|
+
enumerable: true,
|
|
315
403
|
});
|
|
316
404
|
}
|
|
317
405
|
}
|
|
318
|
-
|
|
319
|
-
const originalJson = res.json;
|
|
320
|
-
res.json = function (data) {
|
|
321
|
-
if (req.headers["x-encrypt-response"]) {
|
|
322
|
-
// Encryption using SecureObject
|
|
323
|
-
const secureObj = new SecureObject({
|
|
324
|
-
data: JSON.stringify(data),
|
|
325
|
-
});
|
|
326
|
-
secureObj.setEncryptionKey(self.config.authentication?.jwt?.secret || "default-key");
|
|
327
|
-
secureObj.encryptAll();
|
|
328
|
-
const encrypted = secureObj.exportData();
|
|
329
|
-
res.set("X-Encrypted-Response", "true");
|
|
330
|
-
return originalJson.call(this, { data: encrypted });
|
|
331
|
-
}
|
|
332
|
-
return originalJson.call(this, data);
|
|
333
|
-
};
|
|
334
|
-
next();
|
|
335
|
-
};
|
|
406
|
+
});
|
|
336
407
|
}
|
|
337
408
|
/**
|
|
338
|
-
*
|
|
409
|
+
* Recursively sanitize object properties
|
|
339
410
|
*/
|
|
340
411
|
sanitizeObject(obj) {
|
|
341
412
|
if (typeof obj === "string") {
|
|
342
|
-
return
|
|
413
|
+
return xss(obj);
|
|
343
414
|
}
|
|
344
|
-
if (
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
415
|
+
if (Array.isArray(obj)) {
|
|
416
|
+
return obj.map((item) => this.sanitizeObject(item));
|
|
417
|
+
}
|
|
418
|
+
if (obj && typeof obj === "object") {
|
|
419
|
+
const sanitized = {};
|
|
420
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
421
|
+
sanitized[key] = this.sanitizeObject(value);
|
|
349
422
|
}
|
|
423
|
+
return sanitized;
|
|
350
424
|
}
|
|
351
425
|
return obj;
|
|
352
426
|
}
|
|
353
427
|
/**
|
|
354
|
-
* Sanitize
|
|
355
|
-
*/
|
|
356
|
-
sanitizeString(str) {
|
|
357
|
-
return str
|
|
358
|
-
.replace(/</g, "<")
|
|
359
|
-
.replace(/>/g, ">")
|
|
360
|
-
.replace(/"/g, """)
|
|
361
|
-
.replace(/'/g, "'")
|
|
362
|
-
.replace(/\//g, "/")
|
|
363
|
-
.replace(/javascript:/gi, "")
|
|
364
|
-
.replace(/on\w+=/gi, "");
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Get security configuration
|
|
428
|
+
* Sanitize object and detect threats
|
|
368
429
|
*/
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
430
|
+
sanitizeObjectWithDetection(obj, path = "") {
|
|
431
|
+
const threats = [];
|
|
432
|
+
const sanitizeWithDetection = (value, currentPath) => {
|
|
433
|
+
if (typeof value === "string") {
|
|
434
|
+
const original = value;
|
|
435
|
+
let sanitized = xss(value);
|
|
436
|
+
let threatDetected = false;
|
|
437
|
+
const detectedPatterns = [];
|
|
438
|
+
// Check if XSS library sanitization changed the content
|
|
439
|
+
if (original !== sanitized) {
|
|
440
|
+
threatDetected = true;
|
|
441
|
+
detectedPatterns.push("XSS");
|
|
442
|
+
}
|
|
443
|
+
// SQL Injection Detection
|
|
444
|
+
if (this.sqlInjection) {
|
|
445
|
+
const sqlResult = this.sqlInjectionDetector.detect(original, currentPath);
|
|
446
|
+
if (sqlResult.isMalicious) {
|
|
447
|
+
threatDetected = true;
|
|
448
|
+
detectedPatterns.push(`SQL Injection (${sqlResult.riskLevel})`);
|
|
449
|
+
// Use the SQL detector's sanitized version if available
|
|
450
|
+
if (sqlResult.sanitizedInput) {
|
|
451
|
+
sanitized = sqlResult.sanitizedInput;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
// Additional threat detection for patterns XSS library might miss
|
|
456
|
+
const additionalThreats = [
|
|
457
|
+
/javascript:/i,
|
|
458
|
+
/vbscript:/i,
|
|
459
|
+
/data:/i,
|
|
460
|
+
/on\w+\s*=/i, // event handlers like onclick=, onload=
|
|
461
|
+
/<iframe/i,
|
|
462
|
+
/<object/i,
|
|
463
|
+
/<embed/i,
|
|
464
|
+
/<link/i,
|
|
465
|
+
/<meta/i,
|
|
466
|
+
/expression\s*\(/i, // CSS expression()
|
|
467
|
+
/url\s*\(\s*javascript:/i,
|
|
468
|
+
];
|
|
469
|
+
for (const pattern of additionalThreats) {
|
|
470
|
+
if (pattern.test(original)) {
|
|
471
|
+
threatDetected = true;
|
|
472
|
+
detectedPatterns.push("Enhanced XSS");
|
|
473
|
+
// Sanitize these additional threats
|
|
474
|
+
sanitized = original.replace(pattern, "[BLOCKED]");
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (threatDetected) {
|
|
479
|
+
threats.push(currentPath || "root");
|
|
480
|
+
// Log the specific threats detected
|
|
481
|
+
this.logger.warn("security", `Security threat detected in ${currentPath || "root"}: ${detectedPatterns.join(", ")}`);
|
|
482
|
+
}
|
|
483
|
+
return sanitized;
|
|
385
484
|
}
|
|
386
|
-
|
|
387
|
-
|
|
485
|
+
if (Array.isArray(value)) {
|
|
486
|
+
return value.map((item, index) => sanitizeWithDetection(item, `${currentPath}[${index}]`));
|
|
388
487
|
}
|
|
389
|
-
|
|
390
|
-
|
|
488
|
+
if (value && typeof value === "object") {
|
|
489
|
+
const sanitized = {};
|
|
490
|
+
for (const [key, val] of Object.entries(value)) {
|
|
491
|
+
const newPath = currentPath ? `${currentPath}.${key}` : key;
|
|
492
|
+
sanitized[key] = sanitizeWithDetection(val, newPath);
|
|
493
|
+
}
|
|
494
|
+
return sanitized;
|
|
495
|
+
}
|
|
496
|
+
return value;
|
|
497
|
+
};
|
|
498
|
+
const sanitized = sanitizeWithDetection(obj, path);
|
|
499
|
+
return { sanitized, threats };
|
|
391
500
|
}
|
|
392
501
|
/**
|
|
393
|
-
*
|
|
502
|
+
* Get CSRF token for client-side usage
|
|
394
503
|
*/
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
delete record.blockedUntil;
|
|
399
|
-
record.attempts = 0;
|
|
400
|
-
return true;
|
|
504
|
+
generateCsrfToken(req) {
|
|
505
|
+
if (this.csrf && req.csrfToken) {
|
|
506
|
+
return req.csrfToken();
|
|
401
507
|
}
|
|
402
|
-
return
|
|
508
|
+
return null;
|
|
403
509
|
}
|
|
404
510
|
/**
|
|
405
|
-
*
|
|
511
|
+
* Get security configuration
|
|
406
512
|
*/
|
|
407
|
-
|
|
408
|
-
|
|
513
|
+
getConfig() {
|
|
514
|
+
return {
|
|
515
|
+
level: this.level,
|
|
516
|
+
csrf: this.csrf,
|
|
517
|
+
helmet: this.helmet,
|
|
518
|
+
xss: this.xss,
|
|
519
|
+
sqlInjection: this.sqlInjection,
|
|
520
|
+
bruteForce: this.bruteForce,
|
|
521
|
+
encryption: this.encryption,
|
|
522
|
+
authentication: this.authentication,
|
|
523
|
+
};
|
|
409
524
|
}
|
|
410
525
|
}
|
|
411
526
|
|