mm_os 3.2.9 → 3.3.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/README.md +47 -1
- package/core/base/mqtt/index.js +10 -10
- package/core/base/web/index.js +98 -11
- package/core/com/middleware/com.js +152 -152
- package/core/com/socket/config.tpl.json +2 -2
- package/core/com/socket/drive.js +2 -2
- package/core/com/socket/index.js +1 -1
- package/core/com/sql/drive.js +7 -7
- package/index.js +40 -30
- package/middleware/performance/index.js +150 -142
- package/middleware/security_audit/index.js +549 -0
- package/middleware/security_audit/middleware.json +48 -0
- package/middleware/security_headers/index.js +487 -0
- package/middleware/security_headers/middleware.json +45 -0
- package/middleware/waf/index.js +277 -6
- package/middleware/waf/middleware.json +2 -1
- package/middleware/waf_ddos/index.js +520 -0
- package/middleware/waf_ddos/middleware.json +38 -0
- package/middleware/waf_ip/index.js +231 -20
- package/middleware/waf_ip/middleware.json +43 -4
- package/middleware/waf_xss/index.js +269 -0
- package/middleware/waf_xss/middleware.json +18 -0
- package/middleware/web_before/middleware.json +1 -1
- package/middleware/web_socket/middleware.json +2 -2
- package/package.json +18 -7
- package/middleware/cors/index.js +0 -103
- package/middleware/cors/middleware.json +0 -9
- package/middleware/log/index.js +0 -32
- package/middleware/log/middleware.json +0 -9
- package/middleware/rate_limit/index.js +0 -112
- package/middleware/rate_limit/middleware.json +0 -10
- package/nodemon.json +0 -31
- package/package.txt +0 -1
- package/rps.bat +0 -3
- package/test.js +0 -10
- package/tps.bat +0 -3
- package/update.bat +0 -1
- package//347/263/273/347/273/237/346/236/266/346/236/204/350/257/204/344/274/260/344/270/216/344/274/230/345/214/226/345/273/272/350/256/256.md +0 -599
package/middleware/waf/index.js
CHANGED
|
@@ -23,7 +23,20 @@ function waf_check(url) {
|
|
|
23
23
|
/\<(iframe|script|body|img|layer|div|meta|style|base|object|input)/i,
|
|
24
24
|
/(onmouseover|onmousemove|onerror|onload)\=/i,
|
|
25
25
|
/javascript:/i,
|
|
26
|
-
|
|
26
|
+
// 增强的路径遍历检测规则
|
|
27
|
+
/\.\.\//i, // 基础 ../
|
|
28
|
+
/\.\.\\/i, // Windows格式 ..\
|
|
29
|
+
/\%2e\%2e\//i, // URL编码 ../
|
|
30
|
+
/\%2e%2e\//i, // URL编码 ../
|
|
31
|
+
/\%252e%252e%2f/i, // 双重URL编码 ../
|
|
32
|
+
/\%252e\%252e\%2f/i, // 双重URL编码 ../
|
|
33
|
+
/\.\%2e\//i, // 混合编码
|
|
34
|
+
/\%2e\./i, // 变体形式
|
|
35
|
+
/\%5c/i, // 反斜杠URL编码
|
|
36
|
+
/\%255c/i, // 反斜杠双重URL编码
|
|
37
|
+
// 系统文件路径检测
|
|
38
|
+
/(?:\/etc|\/proc|\/sys|\/dev|C:\\Windows|C:\\winnt|C:\\Program Files)/i,
|
|
39
|
+
// 命令注入检测
|
|
27
40
|
/\|\|.*(?:ls|pwd|whoami|ll|ifconfog|ipconfig|&&|chmod|cd|mkdir|rmdir|cp|mv)/i,
|
|
28
41
|
/(?:ls|pwd|whoami|ll|ifconfog|ipconfig|&&|chmod|cd|mkdir|rmdir|cp|mv).*\|\|/i,
|
|
29
42
|
/(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\//i
|
|
@@ -36,6 +49,98 @@ function waf_check(url) {
|
|
|
36
49
|
return null;
|
|
37
50
|
}
|
|
38
51
|
|
|
52
|
+
/**
|
|
53
|
+
* 检查路径是否包含路径遍历攻击
|
|
54
|
+
* @param {String} path 路径
|
|
55
|
+
* @returns {Boolean} 是否包含路径遍历
|
|
56
|
+
*/
|
|
57
|
+
function checkPathTraversal(path) {
|
|
58
|
+
// 规范化路径以处理各种编码
|
|
59
|
+
let normalizedPath = path;
|
|
60
|
+
|
|
61
|
+
// 处理URL编码变体
|
|
62
|
+
const urlDecoded = decodeURIComponent(path);
|
|
63
|
+
const doubleUrlDecoded = decodeURIComponent(urlDecoded);
|
|
64
|
+
|
|
65
|
+
// 检查路径是否包含危险模式
|
|
66
|
+
const dangerousPatterns = [
|
|
67
|
+
'../', '../../', '../../../', // Unix/Linux格式
|
|
68
|
+
'..\\', '..\\\\', '..\\\\\\', // Windows格式
|
|
69
|
+
'/%2e%2e/', '/%2e%2e%2f', // URL编码变体
|
|
70
|
+
'\\%2e%2e\\', '\\%2e%2e\\\\' // Windows URL编码变体
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
// 检查系统关键文件路径(绝对路径攻击)
|
|
74
|
+
const systemPaths = [
|
|
75
|
+
'/etc/passwd', '/etc/shadow', '/etc/group', '/etc/hosts',
|
|
76
|
+
'/proc/', '/sys/', '/dev/', '/bin/', '/usr/bin/',
|
|
77
|
+
'C:\\Windows\\', 'C:\\winnt\\', 'C:\\Program Files\\'
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
// 检查原始路径、单次解码和双重解码后的路径
|
|
81
|
+
// 1. 检查相对路径遍历模式
|
|
82
|
+
const hasTraversalPattern = dangerousPatterns.some(pattern =>
|
|
83
|
+
path.includes(pattern) ||
|
|
84
|
+
urlDecoded.includes(pattern) ||
|
|
85
|
+
doubleUrlDecoded.includes(pattern)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// 2. 检查绝对路径攻击(包含系统关键文件路径)
|
|
89
|
+
const hasAbsoluteAttack = systemPaths.some(systemPath =>
|
|
90
|
+
path.toLowerCase().includes(systemPath.toLowerCase()) ||
|
|
91
|
+
urlDecoded.toLowerCase().includes(systemPath.toLowerCase()) ||
|
|
92
|
+
doubleUrlDecoded.toLowerCase().includes(systemPath.toLowerCase())
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// 3. 检查是否以/开头的绝对路径(排除正常的网站路径)
|
|
96
|
+
const startsWithSlash = path.startsWith('/') &&
|
|
97
|
+
!path.startsWith('/api') &&
|
|
98
|
+
!path.startsWith('/static') &&
|
|
99
|
+
!path.startsWith('/public') &&
|
|
100
|
+
!path.startsWith('/assets') &&
|
|
101
|
+
!path.startsWith('/favicon.ico') &&
|
|
102
|
+
!path.startsWith('/robots.txt');
|
|
103
|
+
|
|
104
|
+
// 4. 检查是否包含敏感的系统文件扩展名
|
|
105
|
+
const hasSensitiveExtension = /\.(conf|ini|log|env|git|svn|htpasswd|htaccess|bashrc|bash_history|ssh|key|pem|cer|crt|pfx|p12)$/i.test(path) ||
|
|
106
|
+
/\.(conf|ini|log|env|git|svn|htpasswd|htaccess|bashrc|bash_history|ssh|key|pem|cer|crt|pfx|p12)$/i.test(urlDecoded) ||
|
|
107
|
+
/\.(conf|ini|log|env|git|svn|htpasswd|htaccess|bashrc|bash_history|ssh|key|pem|cer|crt|pfx|p12)$/i.test(doubleUrlDecoded);
|
|
108
|
+
|
|
109
|
+
return hasTraversalPattern || hasAbsoluteAttack || startsWithSlash || hasSensitiveExtension;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 检查请求路径是否规范化,防止路径遍历攻击
|
|
114
|
+
* @param {String} path 请求路径
|
|
115
|
+
* @returns {Boolean} 是否为安全路径
|
|
116
|
+
*/
|
|
117
|
+
function isSafePath(path) {
|
|
118
|
+
// 特殊处理根路径,直接返回安全
|
|
119
|
+
if (path === '/') {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 获取规范化的路径
|
|
124
|
+
const normalizedPath = path.split('/')
|
|
125
|
+
.filter(segment => segment !== '')
|
|
126
|
+
.reduce((acc, segment) => {
|
|
127
|
+
// 防止路径回溯
|
|
128
|
+
if (segment === '..') {
|
|
129
|
+
acc.pop();
|
|
130
|
+
} else if (segment !== '.') {
|
|
131
|
+
acc.push(segment);
|
|
132
|
+
}
|
|
133
|
+
return acc;
|
|
134
|
+
}, [])
|
|
135
|
+
.join('/');
|
|
136
|
+
|
|
137
|
+
// 重新构建规范化的完整路径
|
|
138
|
+
const safePath = '/' + normalizedPath;
|
|
139
|
+
|
|
140
|
+
// 检查规范化后的路径长度是否小于原始路径(表示存在路径回溯)
|
|
141
|
+
return safePath.length >= path.length - 2; // 允许末尾的 '/' 差异
|
|
142
|
+
}
|
|
143
|
+
|
|
39
144
|
function getClientIP(req) {
|
|
40
145
|
return req.headers['x-forwarded-for'] || req.headers['X-Forwarded-For'] ||
|
|
41
146
|
req.connection.remoteAddress ||
|
|
@@ -43,20 +148,131 @@ function getClientIP(req) {
|
|
|
43
148
|
req.connection.socket.remoteAddress;
|
|
44
149
|
};
|
|
45
150
|
|
|
151
|
+
/**
|
|
152
|
+
* 检查IP是否在白名单中
|
|
153
|
+
* @param {String} ip IP地址
|
|
154
|
+
* @param {Object} config WAF配置
|
|
155
|
+
* @returns {Boolean} 是否在白名单中
|
|
156
|
+
*/
|
|
157
|
+
function isInWhitelist(ip, config) {
|
|
158
|
+
// 获取配置中的白名单,如果不存在则使用默认白名单
|
|
159
|
+
const whitelist = config && config.ip_whitelist && Array.isArray(config.ip_whitelist)
|
|
160
|
+
? config.ip_whitelist
|
|
161
|
+
: ['127.0.0.1', '::1', 'localhost', '192.168.31.5'];
|
|
162
|
+
|
|
163
|
+
return whitelist.includes(ip);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 检查路径是否在白名单中
|
|
168
|
+
* @param {String} path 请求路径
|
|
169
|
+
* @param {Object} config WAF配置
|
|
170
|
+
* @returns {Boolean} 是否在白名单中
|
|
171
|
+
*/
|
|
172
|
+
function isPathWhitelisted(path, config) {
|
|
173
|
+
// 获取配置中的路径白名单,如果不存在则使用默认路径白名单
|
|
174
|
+
const pathWhitelist = config && config.path_whitelist && Array.isArray(config.path_whitelist)
|
|
175
|
+
? config.path_whitelist
|
|
176
|
+
: ['/static', '/favicon.ico', '/api', '/public', '/assets'];
|
|
177
|
+
|
|
178
|
+
// 检查路径是否以白名单中的任何路径开头
|
|
179
|
+
return pathWhitelist.some(whitelistPath => path.startsWith(whitelistPath));
|
|
180
|
+
}
|
|
181
|
+
|
|
46
182
|
/**
|
|
47
183
|
* web防火墙
|
|
48
184
|
* @param {Object} server 服务
|
|
49
185
|
* @param {Object} config 配置参数
|
|
50
186
|
*/
|
|
51
187
|
module.exports = function(server, config) {
|
|
188
|
+
// 设置默认配置
|
|
189
|
+
const defaultConfig = {
|
|
190
|
+
log: true,
|
|
191
|
+
ip_whitelist: ['127.0.0.1', '::1', 'localhost', '192.168.31.5'],
|
|
192
|
+
path_whitelist: ['/static', '/favicon.ico', '/api', '/public', '/assets']
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// 强制输出初始化日志
|
|
196
|
+
console.log('WAF MIDDLEWARE INITIALIZED');
|
|
197
|
+
|
|
198
|
+
// 获取全局配置中的middleware.waf配置
|
|
199
|
+
let wafConfig = defaultConfig;
|
|
200
|
+
try {
|
|
201
|
+
// 尝试从全局配置中获取middleware.waf配置
|
|
202
|
+
const fs = require('fs');
|
|
203
|
+
const path = require('path');
|
|
204
|
+
const configPath = path.resolve(process.cwd(), 'config.json');
|
|
205
|
+
if (fs.existsSync(configPath)) {
|
|
206
|
+
const globalConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
207
|
+
if (globalConfig.middleware && globalConfig.middleware.waf) {
|
|
208
|
+
// 安全地合并默认配置和全局配置
|
|
209
|
+
wafConfig = Object.assign({}, defaultConfig, globalConfig.middleware.waf);
|
|
210
|
+
console.log('WAF using global config from config.json');
|
|
211
|
+
} else {
|
|
212
|
+
console.log('WAF using default config (no middleware.waf in config.json)');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error('Error loading global WAF config:', error.message);
|
|
217
|
+
// 出错时使用默认配置
|
|
218
|
+
wafConfig = defaultConfig;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 确保白名单数组存在且为数组类型
|
|
222
|
+
if (!Array.isArray(wafConfig.ip_whitelist)) {
|
|
223
|
+
wafConfig.ip_whitelist = defaultConfig.ip_whitelist;
|
|
224
|
+
}
|
|
225
|
+
if (!Array.isArray(wafConfig.path_whitelist)) {
|
|
226
|
+
wafConfig.path_whitelist = defaultConfig.path_whitelist;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 合并传入的config和全局配置
|
|
230
|
+
const mergedConfig = { ...wafConfig, ...(config || {}) };
|
|
231
|
+
console.log('Merged WAF Config:', JSON.stringify(mergedConfig));
|
|
232
|
+
|
|
52
233
|
/* WAF(web防火墙) */
|
|
53
234
|
server.use(async (ctx, next) => {
|
|
54
235
|
try {
|
|
236
|
+
// 获取客户端IP
|
|
237
|
+
var ip = getClientIP(ctx.req);
|
|
238
|
+
// 规范化IP格式,移除IPv6前缀
|
|
239
|
+
if (ip && ip.startsWith('::ffff:')) {
|
|
240
|
+
ip = ip.substring(7);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 获取请求路径
|
|
244
|
+
const path = ctx.path;
|
|
245
|
+
|
|
246
|
+
// 强制输出请求处理日志
|
|
247
|
+
console.log('WAF PROCESSING REQUEST');
|
|
248
|
+
console.log('URL:', ctx.url);
|
|
249
|
+
console.log('Path:', path);
|
|
250
|
+
console.log('Method:', ctx.method);
|
|
251
|
+
console.log('IP:', ip);
|
|
252
|
+
|
|
253
|
+
// 检查IP是否在白名单中,如果是则跳过所有检查
|
|
254
|
+
if (isInWhitelist(ip, mergedConfig)) {
|
|
255
|
+
console.log(`WAF: IP ${ip} in whitelist, skipping checks`);
|
|
256
|
+
await next();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 检查路径是否在白名单中
|
|
261
|
+
if (isPathWhitelisted(path, mergedConfig)) {
|
|
262
|
+
console.log(`WAF: Path ${path} in whitelist, skipping checks`);
|
|
263
|
+
await next();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// 获取请求路径和完整URL
|
|
55
268
|
var url = ctx.url;
|
|
269
|
+
|
|
270
|
+
// 1. 使用正则表达式检查基本攻击特征
|
|
271
|
+
console.log('Step 1: Basic attack pattern check');
|
|
56
272
|
var danger = waf_check(url);
|
|
273
|
+
console.log('WAF check result:', danger ? danger.toString() : 'safe');
|
|
57
274
|
if (danger) {
|
|
58
|
-
|
|
59
|
-
$.log.warn(`检测到来自IP ${ip} 的攻击`, "规则:", danger.toString());
|
|
275
|
+
console.warn(`BLOCKED ATTACK from IP ${ip}:`, danger.toString());
|
|
60
276
|
// 阻止攻击请求,返回403禁止访问
|
|
61
277
|
ctx.status = 403;
|
|
62
278
|
ctx.body = {
|
|
@@ -64,11 +280,66 @@ module.exports = function(server, config) {
|
|
|
64
280
|
msg: '访问被WAF阻止,请求包含潜在的攻击特征',
|
|
65
281
|
rule: danger.toString()
|
|
66
282
|
};
|
|
67
|
-
|
|
68
|
-
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// 2. 专门检查路径遍历攻击
|
|
287
|
+
console.log('Step 2: Path traversal check');
|
|
288
|
+
const hasTraversal = checkPathTraversal(path);
|
|
289
|
+
const isSafe = isSafePath(path);
|
|
290
|
+
console.log('Path traversal check results:', { path, hasTraversal, isSafe });
|
|
291
|
+
|
|
292
|
+
if (hasTraversal || !isSafe) {
|
|
293
|
+
console.warn(`BLOCKED PATH TRAVERSAL from IP ${ip}:`, path);
|
|
294
|
+
ctx.status = 403;
|
|
295
|
+
ctx.body = {
|
|
296
|
+
code: 403,
|
|
297
|
+
msg: '访问被WAF阻止,检测到路径遍历攻击尝试'
|
|
298
|
+
};
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 3. 检查请求参数中的路径遍历
|
|
303
|
+
console.log('Step 3: Query parameter traversal check');
|
|
304
|
+
const queryParams = ctx.query;
|
|
305
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
306
|
+
if (typeof value === 'string') {
|
|
307
|
+
const paramHasTraversal = checkPathTraversal(value);
|
|
308
|
+
console.log('Param check:', { key, value, paramHasTraversal });
|
|
309
|
+
if (paramHasTraversal) {
|
|
310
|
+
console.warn(`BLOCKED PARAM TRAVERSAL from IP ${ip}:`, `${key}=${value}`);
|
|
311
|
+
ctx.status = 403;
|
|
312
|
+
ctx.body = {
|
|
313
|
+
code: 403,
|
|
314
|
+
msg: '访问被WAF阻止,请求参数中包含路径遍历攻击尝试'
|
|
315
|
+
};
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
69
319
|
}
|
|
320
|
+
|
|
321
|
+
// 4. 如果是POST请求,检查请求体
|
|
322
|
+
console.log('Step 4: POST body traversal check');
|
|
323
|
+
if (ctx.method === 'POST' && ctx.request.body) {
|
|
324
|
+
const bodyContent = JSON.stringify(ctx.request.body);
|
|
325
|
+
const bodyHasTraversal = checkPathTraversal(bodyContent);
|
|
326
|
+
console.log('Body check results:', bodyHasTraversal);
|
|
327
|
+
if (bodyHasTraversal) {
|
|
328
|
+
console.warn(`BLOCKED BODY TRAVERSAL from IP ${ip}`);
|
|
329
|
+
ctx.status = 403;
|
|
330
|
+
ctx.body = {
|
|
331
|
+
code: 403,
|
|
332
|
+
msg: '访问被WAF阻止,请求体中包含路径遍历攻击尝试'
|
|
333
|
+
};
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
console.log('WAF: All checks passed, continuing request');
|
|
339
|
+
// 所有检查通过,继续处理请求
|
|
340
|
+
await next();
|
|
70
341
|
} catch (error) {
|
|
71
|
-
|
|
342
|
+
console.error('WAF MIDDLEWARE ERROR:', error);
|
|
72
343
|
// 出错时默认允许请求继续处理
|
|
73
344
|
await next();
|
|
74
345
|
}
|