mm_os 3.2.9 → 3.3.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.
Files changed (56) hide show
  1. package/README.md +47 -1
  2. package/core/base/mqtt/index.js +1109 -1106
  3. package/core/base/web/index.js +245 -156
  4. package/core/com/event/README.md +4 -4
  5. package/core/com/event/com.json +3 -3
  6. package/core/com/event/config.tpl.json +18 -18
  7. package/core/com/event/drive.js +132 -132
  8. package/core/com/event/index.js +344 -344
  9. package/core/com/event/script.js +25 -25
  10. package/core/com/middleware/com.js +152 -151
  11. package/core/com/socket/config.tpl.json +2 -2
  12. package/core/com/socket/drive.js +2 -2
  13. package/core/com/socket/index.js +1 -1
  14. package/core/com/sql/drive.js +7 -7
  15. package/core/com/static/index.js +1 -1
  16. package/index.js +34 -5
  17. package/middleware/cors/index.js +112 -96
  18. package/middleware/cors/middleware.json +18 -7
  19. package/middleware/csrf/index.js +202 -0
  20. package/middleware/csrf/middleware.json +24 -0
  21. package/middleware/ip_firewall/index.js +476 -0
  22. package/middleware/ip_firewall/middleware.json +109 -0
  23. package/middleware/mqtt_base/middleware.json +2 -1
  24. package/middleware/security_audit/index.js +543 -0
  25. package/middleware/security_audit/middleware.json +48 -0
  26. package/middleware/waf/index.js +273 -7
  27. package/middleware/waf/middleware.json +2 -1
  28. package/middleware/waf_ddos/index.js +520 -0
  29. package/middleware/waf_ddos/middleware.json +38 -0
  30. package/middleware/waf_xss/index.js +269 -0
  31. package/middleware/waf_xss/middleware.json +18 -0
  32. package/middleware/web_after/middleware.json +2 -1
  33. package/middleware/web_base/middleware.json +2 -1
  34. package/middleware/web_before/middleware.json +3 -2
  35. package/middleware/web_check/middleware.json +2 -1
  36. package/middleware/web_main/middleware.json +2 -1
  37. package/middleware/web_proxy/middleware.json +2 -1
  38. package/middleware/web_render/middleware.json +2 -1
  39. package/middleware/web_socket/middleware.json +4 -3
  40. package/middleware/web_static/middleware.json +2 -1
  41. package/package.json +28 -15
  42. package/middleware/log/index.js +0 -32
  43. package/middleware/log/middleware.json +0 -9
  44. package/middleware/performance/index.js +0 -143
  45. package/middleware/performance/middleware.json +0 -16
  46. package/middleware/rate_limit/index.js +0 -112
  47. package/middleware/rate_limit/middleware.json +0 -10
  48. package/middleware/waf_ip/index.js +0 -168
  49. package/middleware/waf_ip/middleware.json +0 -10
  50. package/nodemon.json +0 -31
  51. package/package.txt +0 -1
  52. package/rps.bat +0 -3
  53. package/test.js +0 -10
  54. package/tps.bat +0 -3
  55. package/update.bat +0 -1
  56. 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
@@ -1,103 +1,119 @@
1
1
  /**
2
- * 跨域请求
3
- * @param {Object} server 服务
4
- * @param {Object} config 配置参数
2
+ * CORS跨域中间件
3
+ * 处理跨域资源共享(CORS)配置
5
4
  */
6
- module.exports = function(server, config) {
7
- var cos = config.cos;
8
- if (cos && cos.status) {
9
- if (cos.headers && cos.origin !== "*") {
10
- /* 跨域限制(web防火墙) */
11
- server.use(async (ctx, next) => {
12
- try {
13
- var req = ctx.request;
5
+ class CorsMiddleware {
6
+ constructor() {
7
+ this.default = {
8
+ // 启用CORS
9
+ enable: true,
10
+ // 允许的源
11
+ origin: '*',
12
+ // 允许的请求头
13
+ headers: '*',
14
+ // 允许的HTTP方法
15
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD'],
16
+ // 允许携带凭证
17
+ credentials: false,
18
+ // 预检请求的有效期(秒)
19
+ max_age: 3600,
20
+ // 暴露的响应头
21
+ expose_headers: [],
22
+ // 忽略的路径
23
+ ignore_paths: []
24
+ };
25
+ }
26
+ }
14
27
 
15
- // 允许来自所有域名请求
16
- ctx.set('Access-Control-Allow-Origin', cos.origin);
17
- // 这样就能只允许 http://localhost:8080 这个域名的请求了
18
- // ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");
28
+ CorsMiddleware.prototype.init = function(config) {
29
+ this.config = Object.assign({}, this.default, config || {});
30
+ return this;
31
+ };
19
32
 
20
- // 字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段.
21
- if (req.method == "OPTIONS") {
22
- ctx.set('Access-Control-Allow-Headers', cos.headers);
33
+ CorsMiddleware.prototype.run = async function(ctx, next) {
34
+ const config = this.config;
35
+
36
+ if (!config.enable) {
37
+ return await next();
38
+ }
39
+
40
+ // 检查是否应该忽略该路径
41
+ const path = ctx.path;
42
+ if (config.ignore_paths.some(p => path.startsWith(p))) {
43
+ return await next();
44
+ }
45
+
46
+ // 设置CORS头
47
+ this._setCorsHeaders(ctx, config);
48
+
49
+ // 处理预检请求
50
+ if (ctx.method === 'OPTIONS') {
51
+ ctx.status = 204;
52
+ return;
53
+ }
54
+
55
+ await next();
56
+ };
23
57
 
24
- // 服务器收到请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。
25
- // Content-Type表示具体请求中的媒体类型信息
26
- // ctx.set("Content-Type", "application/json;charset=utf-8");
27
- // 设置所允许的HTTP请求方法PUT,POST,GET,DELETE,HEAD,OPTIONS
28
- // ctx.set('Access-Control-Allow-Methods', 'GET,POST');
58
+ CorsMiddleware.prototype._setCorsHeaders = function(ctx, config) {
59
+ // 设置Access-Control-Allow-Origin
60
+ if (config.origin === '*') {
61
+ ctx.set('Access-Control-Allow-Origin', '*');
62
+ } else if (Array.isArray(config.origin)) {
63
+ const requestOrigin = ctx.get('Origin');
64
+ if (config.origin.includes(requestOrigin)) {
65
+ ctx.set('Access-Control-Allow-Origin', requestOrigin);
66
+ }
67
+ } else {
68
+ ctx.set('Access-Control-Allow-Origin', config.origin);
69
+ }
70
+
71
+ // 设置Access-Control-Allow-Headers
72
+ if (config.headers === '*') {
73
+ ctx.set('Access-Control-Allow-Headers', '*');
74
+ } else if (Array.isArray(config.headers)) {
75
+ ctx.set('Access-Control-Allow-Headers', config.headers.join(', '));
76
+ } else {
77
+ ctx.set('Access-Control-Allow-Headers', config.headers);
78
+ }
79
+
80
+ // 设置Access-Control-Allow-Methods
81
+ ctx.set('Access-Control-Allow-Methods', config.methods.join(', '));
82
+
83
+ // 设置Access-Control-Allow-Credentials
84
+ if (config.credentials) {
85
+ ctx.set('Access-Control-Allow-Credentials', 'true');
86
+ }
87
+
88
+ // 设置Access-Control-Max-Age
89
+ if (config.max_age > 0) {
90
+ ctx.set('Access-Control-Max-Age', config.max_age.toString());
91
+ }
92
+
93
+ // 设置Access-Control-Expose-Headers
94
+ if (config.expose_headers.length > 0) {
95
+ ctx.set('Access-Control-Expose-Headers', config.expose_headers.join(', '));
96
+ }
97
+ };
29
98
 
30
- // 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。
31
- // 当设置成允许请求携带cookie时,需要保证"Access-Control-Allow-Origin"是服务器有的域名,而不能是"*";
32
- // ctx.set("Access-Control-Allow-Credentials", 'false');
99
+ // 创建中间件实例
100
+ const middleware = new CorsMiddleware();
33
101
 
34
- // 该字段可选,用来指定本次预检请求的有效期,单位为秒。
35
- // 当请求方法是PUT或DELETE等特殊方法或者Content-Type字段的类型是application/json时,服务器会提前发送一次请求进行验证
36
- // 下面的的设置只本次验证的有效时间,即在该时间段内服务端可以不用进行验证
37
- // ctx.set("Access-Control-Max-Age", '3600');
38
- /*
39
- CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:
40
- Cache-Control、
41
- Content-Language、
42
- Content-Type、
43
- Expires、
44
- Last-Modified、
45
- Pragma
46
- */
47
- // 需要获取其他字段时,使用Access-Control-Expose-Headers,
48
- // getResponseHeader('myData')可以返回我们所需的值
49
- // ctx.set("Access-Control-Expose-Headers", "myData");
50
- ctx.status = 204;
51
- } else {
52
- await next();
53
- }
54
- } catch (error) {
55
- $.log.error('CORS中间件错误(origin限制):', error);
56
- // 出错时默认允许请求继续处理
57
- await next();
58
- }
59
- });
60
- } else if (cos.headers && cos.headers !== "*") {
61
- /* 跨域限制(web防火墙) */
62
- server.use(async (ctx, next) => {
63
- try {
64
- var req = ctx.request;
65
- // 允许来自所有域名请求
66
- ctx.set('Access-Control-Allow-Origin', '*');
67
- // ctx.set('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
68
- if (req.method === 'OPTIONS') {
69
- ctx.set('Access-Control-Allow-Headers', cos.headers);
70
- ctx.status = 204;
71
- } else {
72
- await next();
73
- }
74
- } catch (error) {
75
- $.log.error('CORS中间件错误(headers限制):', error);
76
- // 出错时默认允许请求继续处理
77
- await next();
78
- }
79
- });
80
- } else {
81
- /* 跨域限制(web防火墙) */
82
- server.use(async (ctx, next) => {
83
- try {
84
- var req = ctx.request;
85
- // 允许来自所有域名请求
86
- ctx.set('Access-Control-Allow-Origin', '*');
87
- // ctx.set('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
88
- if (req.method === 'OPTIONS') {
89
- ctx.set('Access-Control-Allow-Headers', '*');
90
- ctx.status = 204;
91
- } else {
92
- await next();
93
- }
94
- } catch (error) {
95
- $.log.error('CORS中间件错误(完全宽松):', error);
96
- // 出错时默认允许请求继续处理
97
- await next();
98
- }
99
- });
100
- }
101
- }
102
- return server;
103
- };
102
+ // 导出符合系统期望的函数
103
+ exports = module.exports = function(server, config) {
104
+ // 初始化中间件
105
+ middleware.init(config);
106
+
107
+ // 注册中间件到服务器
108
+ server.use(middleware.run.bind(middleware));
109
+
110
+ // 记录中间件初始化信息
111
+ if ($.log && $.log.info) {
112
+ $.log.info(`CORS中间件已加载: 启用=${middleware.config.enable}, 源=${middleware.config.origin}`);
113
+ }
114
+
115
+ return server;
116
+ };
117
+
118
+ // 保留原始实例,以便其他方式调用
119
+ exports.middleware = middleware;
@@ -1,9 +1,20 @@
1
1
  {
2
- "name": "web_cors",
3
- "title": "web跨域请求",
4
- "description": "用于跨域请求限制",
5
- "version": "1.0",
6
- "type": "web",
7
- "process_type": "common_before",
8
- "sort": 50
2
+ "name": "cors",
3
+ "title": "CORS跨域中间件",
4
+ "description": "处理跨域资源共享(CORS)配置,支持灵活的跨域策略",
5
+ "version": "1.0",
6
+ "type": "web",
7
+ "process_type": "common_before",
8
+ "sort": 15,
9
+ "state": 1,
10
+ "config": {
11
+ "enable": true,
12
+ "origin": "*",
13
+ "headers": "*",
14
+ "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"],
15
+ "credentials": false,
16
+ "max_age": 3600,
17
+ "expose_headers": [],
18
+ "ignore_paths": []
19
+ }
9
20
  }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * CSRF保护中间件
3
+ * 防止跨站请求伪造攻击
4
+ */
5
+ class CsrfMiddleware {
6
+ constructor() {
7
+ this.default = {
8
+ // 启用CSRF保护
9
+ enable: true,
10
+ // CSRF令牌的Cookie名称
11
+ cookie_name: 'csrf_token',
12
+ // CSRF令牌的请求头名称
13
+ header_name: 'X-CSRF-Token',
14
+ // CSRF令牌的表单字段名称
15
+ form_field: '_csrf',
16
+ // CSRF令牌的过期时间(毫秒)
17
+ max_age: 3600000, // 1小时
18
+ // 忽略的HTTP方法
19
+ ignore_methods: ['GET', 'HEAD', 'OPTIONS'],
20
+ // 忽略的路径
21
+ ignore_paths: [],
22
+ // 是否生成新的令牌
23
+ generate_new: true,
24
+ // 是否验证来源
25
+ check_origin: true,
26
+ // 是否记录CSRF攻击尝试
27
+ log: true,
28
+ // 是否阻止恶意请求
29
+ block: true,
30
+ // 允许的来源域名
31
+ allowed_origins: []
32
+ };
33
+ }
34
+ }
35
+
36
+ CsrfMiddleware.prototype.init = function(config) {
37
+ this.config = Object.assign({}, this.default, config || {});
38
+ return this;
39
+ };
40
+
41
+ CsrfMiddleware.prototype.run = async function(ctx, next) {
42
+ const config = this.config;
43
+
44
+ if (!config.enable) {
45
+ return await next();
46
+ }
47
+
48
+ // 生成CSRF令牌
49
+ const token = await this._generateToken(ctx);
50
+
51
+ // 将令牌添加到上下文,供模板使用
52
+ ctx.state.csrf = token;
53
+
54
+ // 检查是否需要验证CSRF
55
+ if (!this._shouldSkipCsrfValidation(ctx, config)) {
56
+ // 验证来源
57
+ if (config.check_origin && !this._validateOrigin(ctx, config)) {
58
+ if (config.block) {
59
+ ctx.status = 403;
60
+ ctx.body = {
61
+ code: 403,
62
+ msg: 'Forbidden: Invalid request origin'
63
+ };
64
+ return;
65
+ }
66
+ }
67
+
68
+ // 验证CSRF令牌
69
+ if (!this._validateToken(ctx, config)) {
70
+ if (config.block) {
71
+ ctx.status = 403;
72
+ ctx.body = {
73
+ code: 403,
74
+ msg: 'Forbidden: Invalid CSRF token'
75
+ };
76
+ return;
77
+ }
78
+ }
79
+
80
+ // 如果需要生成新令牌
81
+ if (config.generate_new) {
82
+ await this._setNewToken(ctx, config);
83
+ }
84
+ }
85
+
86
+ await next();
87
+ };
88
+
89
+ CsrfMiddleware.prototype._generateToken = async function(ctx) {
90
+ let token = ctx.cookies.get(this.config.cookie_name);
91
+
92
+ // 如果没有令牌或需要生成新令牌,则创建一个新的
93
+ if (!token || this.config.generate_new) {
94
+ await this._setNewToken(ctx, this.config);
95
+ token = ctx.cookies.get(this.config.cookie_name);
96
+ }
97
+
98
+ return token;
99
+ };
100
+
101
+ CsrfMiddleware.prototype._setNewToken = async function(ctx, config) {
102
+ // 生成随机令牌
103
+ const token = this._createRandomToken();
104
+
105
+ // 将令牌存储到Cookie
106
+ ctx.cookies.set(config.cookie_name, token, {
107
+ httpOnly: false, // CSRF令牌需要从前端读取,所以不能设置httpOnly
108
+ maxAge: config.max_age,
109
+ sameSite: 'lax'
110
+ });
111
+ };
112
+
113
+ CsrfMiddleware.prototype._createRandomToken = function() {
114
+ return Math.random().toString(36).substring(2) +
115
+ Math.random().toString(36).substring(2) +
116
+ Math.random().toString(36).substring(2);
117
+ };
118
+
119
+ CsrfMiddleware.prototype._shouldSkipCsrfValidation = function(ctx, config) {
120
+ const method = ctx.method;
121
+ const path = ctx.path;
122
+
123
+ // 检查是否在忽略的方法列表中
124
+ if (config.ignore_methods.includes(method)) {
125
+ return true;
126
+ }
127
+
128
+ // 检查是否在忽略的路径列表中
129
+ if (config.ignore_paths.some(p => path.startsWith(p))) {
130
+ return true;
131
+ }
132
+
133
+ return false;
134
+ };
135
+
136
+ CsrfMiddleware.prototype._validateOrigin = function(ctx, config) {
137
+ const origin = ctx.get('Origin');
138
+ const host = ctx.get('Host');
139
+
140
+ // 如果没有Origin头,可能是同源请求
141
+ if (!origin) {
142
+ return true;
143
+ }
144
+
145
+ // 检查是否在允许的来源列表中
146
+ if (config.allowed_origins.length > 0) {
147
+ return config.allowed_origins.includes(origin);
148
+ }
149
+
150
+ // 默认情况下,只允许同源请求
151
+ return origin.includes(host);
152
+ };
153
+
154
+ CsrfMiddleware.prototype._validateToken = function(ctx, config) {
155
+ const tokenFromCookie = ctx.cookies.get(config.cookie_name);
156
+
157
+ // 从请求头获取令牌
158
+ const tokenFromHeader = ctx.get(config.header_name);
159
+
160
+ // 从请求体获取令牌
161
+ let tokenFromBody = null;
162
+ if (ctx.request.body && ctx.request.body[config.form_field]) {
163
+ tokenFromBody = ctx.request.body[config.form_field];
164
+ }
165
+
166
+ // 从查询参数获取令牌
167
+ const tokenFromQuery = ctx.query[config.form_field];
168
+
169
+ // 检查令牌是否匹配
170
+ const receivedToken = tokenFromHeader || tokenFromBody || tokenFromQuery;
171
+
172
+ if (!receivedToken || !tokenFromCookie) {
173
+ return false;
174
+ }
175
+
176
+ return receivedToken === tokenFromCookie;
177
+ };
178
+
179
+ // 创建中间件实例
180
+ const middleware = new CsrfMiddleware();
181
+
182
+ // 导出符合系统期望的函数
183
+ exports = module.exports = function(server, config) {
184
+ // 获取当前中间件的配置(从middleware.json加载的配置)
185
+ var middleware_config = this && this.config ? this.config : config;
186
+
187
+ // 初始化中间件
188
+ middleware.init(middleware_config);
189
+
190
+ // 注册中间件到服务器
191
+ server.use(middleware.run.bind(middleware));
192
+
193
+ // 记录中间件初始化信息
194
+ if ($.log && $.log.info) {
195
+ $.log.info(`CSRF中间件已加载: 启用=${middleware.config.enable}, 忽略路径=${middleware.config.ignore_paths.length}`);
196
+ }
197
+
198
+ return server;
199
+ };
200
+
201
+ // 保留原始实例,以便其他方式调用
202
+ exports.middleware = middleware;
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "csrf",
3
+ "title": "CSRF保护中间件",
4
+ "description": "防止跨站请求伪造攻击,提供安全的令牌验证机制",
5
+ "version": "1.0",
6
+ "type": "web",
7
+ "process_type": "common_before",
8
+ "sort": 20,
9
+ "state": 1,
10
+ "config": {
11
+ "enable": true,
12
+ "cookie_name": "csrf_token",
13
+ "header_name": "X-CSRF-Token",
14
+ "form_field": "_csrf",
15
+ "max_age": 3600000,
16
+ "ignore_methods": ["GET", "HEAD", "OPTIONS"],
17
+ "ignore_paths": ["/api/user/sign_in", "/user/login", "/login", "/admin/login"],
18
+ "generate_new": true,
19
+ "check_origin": true,
20
+ "log": true,
21
+ "block": true,
22
+ "allowed_origins": []
23
+ }
24
+ }