@microi.net/cli 5.7.7 → 5.7.9

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 (191) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/LICENSE +21 -21
  7. package/README.md +71 -71
  8. package/assets/build-meta.json +6 -6
  9. package/assets/feature-matrix.json +138 -138
  10. package/assets/logo.svg +4 -4
  11. package/cordis.patch.yml +1 -1
  12. package/package.json +1 -1
  13. package/scripts/mcp-codex-stdio-adapter.js +0 -0
  14. package/scripts/mcp-server.js +102 -101
  15. package/scripts/microi-cli.js +57 -57
  16. package/scripts/microi-codex-broker.js +450 -450
  17. package/scripts/microi-codex-router.js +0 -0
  18. package/scripts/microi-skills.meta.json +366 -366
  19. package/skills/.microi-skills-version.json +2 -2
  20. package/skills/.progressive-disclosure-manifest.json +27 -27
  21. package/skills/README.md +286 -286
  22. package/skills/ai-engine/SKILL.md +265 -265
  23. package/skills/ai-engine/agents/openai.yaml +4 -4
  24. package/skills/ai-platform-governance/SKILL.md +177 -177
  25. package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -190
  26. package/skills/app-store/SKILL.md +392 -396
  27. package/skills/app-store/agents/openai.yaml +4 -4
  28. package/skills/business-blueprint/SKILL.md +193 -193
  29. package/skills/datasource-engine/SKILL.md +90 -90
  30. package/skills/datasource-engine/agents/openai.yaml +4 -4
  31. package/skills/dos-orm/references/api-reference.md +229 -229
  32. package/skills/email-engine/SKILL.md +78 -78
  33. package/skills/email-engine/references/v8-email.md +34 -34
  34. package/skills/job-engine/SKILL.md +171 -172
  35. package/skills/job-engine/agents/openai.yaml +4 -4
  36. package/skills/message-notification/SKILL.md +155 -156
  37. package/skills/message-notification/agents/openai.yaml +5 -5
  38. package/skills/message-notification/references/contracts.md +102 -102
  39. package/skills/microi-ai-app-auth.js +652 -652
  40. package/skills/microi-ai-application/SKILL.md +102 -106
  41. package/skills/microi-ai-application/agents/openai.yaml +4 -4
  42. package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
  43. package/skills/microi-client-frontend/SKILL.md +235 -240
  44. package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +144 -144
  45. package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +196 -196
  46. package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +167 -167
  47. package/skills/microi-codex/SKILL.md +75 -75
  48. package/skills/microi-codex-installer/SKILL.md +225 -223
  49. package/skills/microi-codex-installer/agents/openai.yaml +7 -7
  50. package/skills/microi-datasource-mapping/SKILL.md +107 -111
  51. package/skills/microi-db-schema/SKILL.md +175 -175
  52. package/skills/microi-db-schema/agents/openai.yaml +4 -4
  53. package/skills/microi-db-schema/references/core-tables.md +695 -695
  54. package/skills/microi-db-schema/references/form-component-options.md +256 -256
  55. package/skills/microi-db-schema/references/schema-overview.md +202 -202
  56. package/skills/microi-db-schema/references/schema.md +646 -646
  57. package/skills/microi-db-schema/references/table-catalog.md +1599 -1599
  58. package/skills/microi-deployment/references/deployment-matrix.md +101 -101
  59. package/skills/microi-docs-coverage/references/capability-map.md +0 -1
  60. package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
  61. package/skills/microi-form-engine/SKILL.md +226 -226
  62. package/skills/microi-form-engine/references/component-catalog.md +216 -216
  63. package/skills/microi-form-engine/references/data-source-events.md +124 -124
  64. package/skills/microi-form-layout/SKILL.md +205 -205
  65. package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -235
  66. package/skills/microi-frontend-sdk/SKILL.md +188 -188
  67. package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +176 -176
  68. package/skills/microi-left-right-layout/SKILL.md +141 -141
  69. package/skills/microi-microservice/SKILL.md +322 -323
  70. package/skills/microi-microservice/references/runtime-delivery.md +278 -278
  71. package/skills/microi-mobile-app-quality/SKILL.md +181 -181
  72. package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +213 -213
  73. package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +128 -128
  74. package/skills/microi-solution-quotation/SKILL.md +78 -78
  75. package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
  76. package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
  77. package/skills/microi-sso/references/acceptance.md +49 -49
  78. package/skills/microi-sso/references/configuration-and-security.md +53 -53
  79. package/skills/microi-sso/references/inbound.md +53 -53
  80. package/skills/microi-sso/references/outbound.md +39 -39
  81. package/skills/microi-system-delivery/SKILL.md +134 -134
  82. package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +193 -193
  83. package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +189 -189
  84. package/skills/microi-ui/SKILL.md +174 -174
  85. package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -183
  86. package/skills/microi-uniapp-frontend/SKILL.md +193 -193
  87. package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +225 -225
  88. package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -154
  89. package/skills/microi.v8.js +1921 -1921
  90. package/skills/module-engine/SKILL.md +237 -250
  91. package/skills/module-engine/references/module-config.md +204 -204
  92. package/skills/ocr-engine/SKILL.md +113 -113
  93. package/skills/ocr-engine/agents/openai.yaml +4 -4
  94. package/skills/page-engine/SKILL.md +180 -191
  95. package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -234
  96. package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -60
  97. package/skills/performance-testing/SKILL.md +221 -221
  98. package/skills/playwright-e2e/SKILL.md +197 -197
  99. package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +173 -173
  100. package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +183 -183
  101. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -221
  102. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +115 -115
  103. package/skills/print-engine/SKILL.md +259 -259
  104. package/skills/production-readonly-audit/SKILL.md +41 -41
  105. package/skills/report-engine/SKILL.md +71 -71
  106. package/skills/report-engine/agents/openai.yaml +4 -4
  107. package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
  108. package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
  109. package/skills/search-engine/SKILL.md +75 -75
  110. package/skills/search-engine/agents/openai.yaml +4 -4
  111. package/skills/spider-engine/SKILL.md +190 -190
  112. package/skills/system-observability/SKILL.md +238 -238
  113. package/skills/system-observability/references/memory-incident-triage.md +70 -70
  114. package/skills/translate-engine/SKILL.md +140 -140
  115. package/skills/translate-engine/agents/openai.yaml +4 -4
  116. package/skills/ui-design/SKILL.md +191 -191
  117. package/skills/ui-design/assets/templates/MCI-DESIGN.md +198 -198
  118. package/skills/ui-design/references/design-pattern-library.md +184 -184
  119. package/skills/ui-design/references/mci-design-contract.md +163 -163
  120. package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -218
  121. package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +137 -137
  122. package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -235
  123. package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -152
  124. package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -238
  125. package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -194
  126. package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -207
  127. package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +117 -117
  128. package/skills/uniapp-mall-assets/SKILL.md +176 -176
  129. package/skills/unity-integration/SKILL.md +155 -155
  130. package/skills/unity-integration/agents/openai.yaml +4 -4
  131. package/skills/unity-integration/references/ai-app-delivery.md +103 -103
  132. package/skills/unity-integration/references/sdk-api.md +82 -82
  133. package/skills/unity-integration/references/toolbox-migration.md +66 -66
  134. package/skills/unity-integration/references/webgl-hosting.md +57 -57
  135. package/skills/v8-cache-pattern/SKILL.md +306 -306
  136. package/skills/v8-crud-api/SKILL.md +175 -175
  137. package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -226
  138. package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -49
  139. package/skills/v8-debugging/SKILL.md +284 -284
  140. package/skills/v8-explorer-tree/SKILL.md +228 -228
  141. package/skills/v8-export-import/SKILL.md +209 -209
  142. package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -211
  143. package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -202
  144. package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -42
  145. package/skills/v8-file-upload/SKILL.md +256 -263
  146. package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +101 -101
  147. package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +150 -150
  148. package/skills/v8-formengine-http/SKILL.md +219 -219
  149. package/skills/v8-frontend-events/SKILL.md +178 -178
  150. package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
  151. package/skills/v8-frontend-events/references/bluetooth-print.md +246 -246
  152. package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -219
  153. package/skills/v8-http-integration/SKILL.md +182 -182
  154. package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -220
  155. package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -44
  156. package/skills/v8-image-processing/SKILL.md +190 -190
  157. package/skills/v8-image-processing/agents/openai.yaml +4 -4
  158. package/skills/v8-image-processing/references/api-reference.md +623 -623
  159. package/skills/v8-menu-buttons/SKILL.md +180 -180
  160. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +222 -222
  161. package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +228 -228
  162. package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -104
  163. package/skills/v8-mongodb/SKILL.md +192 -192
  164. package/skills/v8-mq-mqtt/SKILL.md +175 -176
  165. package/skills/v8-mq-mqtt/references/mqtt-production.md +342 -342
  166. package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -181
  167. package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
  168. package/skills/v8-saas-multi-tenant/SKILL.md +219 -219
  169. package/skills/v8-security/SKILL.md +168 -168
  170. package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +198 -198
  171. package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +158 -158
  172. package/skills/v8-sql-query/SKILL.md +302 -302
  173. package/skills/v8-table-event/SKILL.md +144 -144
  174. package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +197 -197
  175. package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +46 -46
  176. package/skills/v8-tcp-integration/SKILL.md +147 -147
  177. package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
  178. package/skills/v8-template-engine/SKILL.md +167 -167
  179. package/skills/v8-utilities/SKILL.md +90 -90
  180. package/skills/v8-utilities/references/client-api-index.md +143 -143
  181. package/skills/v8-utilities/references/platform-http-routes.md +83 -83
  182. package/skills/v8-utilities/references/server-api-index.md +188 -188
  183. package/skills/v8-workflow/SKILL.md +216 -243
  184. package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -180
  185. package/skills/vision-engine/SKILL.md +159 -159
  186. package/skills/vision-engine/agents/openai.yaml +4 -4
  187. package/skills/vision-engine/references/architecture-and-acceptance.md +194 -194
  188. package/skills/workspace-conventions/SKILL.md +261 -261
  189. package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +208 -208
  190. package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +216 -216
  191. package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +27 -27
@@ -1,158 +1,158 @@
1
- # v8-security 详细参考 2
2
-
3
- > 按需读取;本文件由 SKILL.md 的原章节无损拆分。
4
-
5
- <!-- microi-progressive:chunk id=v8-security-008 sha256=6e0b7de3cd72cc030c93566c03ddf2191af6163d378e5ec8a40828eee9873477 -->
6
- ## 7. 日志记录
7
-
8
- 关键操作必须记录审计日志:
9
-
10
- ```javascript
11
- // 记录敏感操作
12
- V8.Method.AddSysLog({
13
- Title: '删除用户',
14
- Content: JSON.stringify({
15
- OperatorId: V8.CurrentUser.Id,
16
- OperatorName: V8.CurrentUser.Name,
17
- TargetId: V8.Param.userId,
18
- Time: DateNow('yyyy-MM-dd HH:mm:ss')
19
- }),
20
- Type: '安全审计',
21
- Level: 2
22
- });
23
- ```
24
-
25
- ### 管理员吊销用户全部登录态
26
-
27
- 需要让某个用户所有终端立即退出时,接口引擎必须调用平台统一能力,不要只删除前端 Token,也不要只修改用户状态:
28
-
29
- ```javascript
30
- if (!V8.CurrentUser || Number(V8.CurrentUser.Level || 0) < 9999) {
31
- return { Code: 0, Msg: '仅系统管理员可执行此操作' };
32
- }
33
-
34
- var clearResult = V8.Method.ClearUserLoginInfo(V8.Param.UserId, V8.OsClient);
35
- if (clearResult.Code != 1) {
36
- return clearResult;
37
- }
38
- ```
39
-
40
- - `ClearUserLoginInfo` 会删除该用户 Redis 中的全部终端 Token,旧 Token 随即失效且不能继续以旧换新。
41
- - 已建立实时连接的终端会收到 `ReceiveForceLogout` 并立即退出;没有实时连接的终端在下一次请求时收到 Token 失效。
42
- - “禁用用户”必须先吊销全部登录态,再把 `sys_user.State` 更新为 `0`,并记录安全审计日志。
43
- - 接口引擎和底层方法都必须校验管理员权限、目标用户 Id 和租户边界,禁止跨租户吊销。
44
-
45
- <!-- /microi-progressive:chunk -->
46
- <!-- microi-progressive:chunk id=v8-security-009 sha256=b7a65ce2785a6a3d02dc1bc08c16c5ae03e38aa199d4bc204abe5978057f1ea1 -->
47
- ## 8. 错误处理
48
-
49
- 不要把内部错误信息暴露给前端:
50
-
51
- ```javascript
52
- try {
53
- var result = V8.Db.FromSql('SELECT * FROM t WHERE Id = @p0')
54
- .AddInParameter("@p0", V8.Param.id)
55
- .ToArray();
56
- return { Code: 1, Data: result };
57
- } catch (ex) {
58
- // 内部日志使用追踪号和必要的非敏感字段;不要记录完整V8.Param
59
- var traceId = V8.Method.NewUlid();
60
- console.error('查询失败 traceId=' + traceId + ' error=' + ex.message);
61
- // 返回给前端的信息不含内部细节
62
- return { Code: 0, Msg: '查询失败,请稍后重试', DataAppend: { TraceId: traceId } };
63
- }
64
- ```
65
-
66
- <!-- /microi-progressive:chunk -->
67
- <!-- microi-progressive:chunk id=v8-security-010 sha256=4b68e2730cc6ac2ba8eeb4458c71e9ee157b9ac8054dcab364f364b2e0bd1c05 -->
68
- ## 9. Token、终端会话与租户隔离
69
-
70
- 开发 Web、H5、UniApp、小程序、App、VS Code 或 MCP 客户端时,必须同时遵守 `microi-frontend-sdk/SKILL.md` 的 Token 协议:登录传 `_ClientType`,请求头传稳定 `did`,每次响应接收新的 `authorization`,并在浏览器/应用恢复前台时检查续签。
71
-
72
- - PC 默认使用 `SessionAuthTimeout` 分钟策略;移动端、VS Code、MCP 默认使用 `AccessTokenLifetime` 天策略。不要在前端自行扩大服务端有效期。
73
- - Token 的 `OsClient` 必须与当前请求租户一致。收到 `TenantMismatch` 时立即停止请求,不能自动把 Token 复制到另一个租户。
74
- - 收到 `JwtExpired`、`SessionExpired`、`SessionMissing`、`AuthVersionChanged` 时清理当前连接的 Token;多服务器或多租户客户端只能清理受影响的连接,不能全局退出其它连接。
75
- - 收到 `TokenReplaced` 时先检查同一终端是否已有新 Token,避免并发旧响应误清新登录态。
76
- - 用户提示可以显示过期时长、终端类型和租户 Key,但日志、Toast、URL、截图禁止输出完整 Token。
77
-
78
- ### IP 高频拦截、受信 VS Code 独立阈值与解除
79
-
80
- - `DataAppend.SecurityBlocked=true` 是服务端已可达但当前 IP 被临时拦截,不是网络断开。前端必须展示原始 `Msg`、`Reason`、`ExpiresAtUtc`、IP 和解除建议;不能把它转换成“后端 API 服务暂时不可用”。直接返回该结果的安全中间件必须在 CORS 之后。
81
- - 普通访问默认阈值为 10 秒 600 请求/120 异常。VS Code 多服务器源码拉取不能通过减少并发或请求量规避;符合条件的只读 V8Debug `Get/List` 使用独立桶,默认 10 秒 6000 请求/1200 异常。
82
- - 受信判断必须同时满足:服务端共享登录态确认 `Level >= 9999`、请求 Token 是活动 `ClientType=VSCode` Token、请求 `did` 与该 Token 保存的 Did 完全一致、路由为只读 `/api/V8Debug/Get*` 或 `/api/V8Debug/List*`。自报 `ClientType`、User-Agent、`X-User-Level`、单独伪造 did 都不可信;Update/Create/Execute/Upload/Finalize 和 FormEngine 写入不放宽。
83
- - 普通请求的计数 scope 固定为当前 API 主运行实例,不能使用请求方可控的 `OsClient` Query/Header 选择 Redis 桶;只有已通过上述联合校验的 VS Code profile 才能使用活动 Token 服务端绑定的租户 scope。测试必须覆盖轮换两个真实租户 Key 仍落入同一普通桶。
84
- - SecurityGuard 只读取 `Connection.RemoteIpAddress`,不得直接解析 `X-Forwarded-For`/`X-Real-IP`。容器运行时可自动信任当前容器路由表实际发现的 RFC1918/ULA 私有默认网关**精确 IP**,用于宿主 Nginx 经 Docker 发布端口转发的最后一跳;不得自动信任公网网关或任意私有网段。其它代理只信任主租户 SaaS 引擎【后端运行配置】的 `BackendForwardedKnownProxies` 精确 IP 和 `BackendForwardedKnownNetworks` 受控 CIDR;禁止使用环境变量、自定义 `appsettings` 节点、`0.0.0.0/0` 或 `::/0`。历史 `SecurityRespectForwardedHeaders` 字段不能建立 Header 信任。该宿主配置变更需滚动重启节点,测试必须覆盖容器网关把 XFF 投影为真实 IP,以及公网 Remote IP 携带伪造 `X-Forwarded-For: 127.0.0.1` 时仍识别公网 IP。
85
- - `UseForwardedHeaders` 后若 Remote IP 仍是自动发现的精确容器网关,表示代理未提供可验证的客户端地址;该请求不得进入按 IP 自动封禁,否则任一用户可导致全站误封。此降级不跳过后续全局请求压力、内存和业务鉴权,公网或普通私网地址也不适用;运维仍应补齐最后一跳转发头。
86
- - IP 错误窗口只把未匹配端点的 404/405 作为扫描计数;400/401/403/413/429、5xx、已匹配 Controller 以及 `/api`、`/apiengine` 动态路由的应用级 404/405 只能审计,不能触发自动封禁。请求总量窗口继续作为独立的高频攻击门禁,禁止用服务端故障或正常业务拒绝反向惩罚客户端。
87
- - 旧版 `HighError`/`TrustedVsCodeHighError` 宽泛错误策略产生的自动封禁属于可识别的失效状态;升级节点应从共享 Redis 和本机缓存幂等退休,不能要求所有租户等待旧 TTL,也不能解除手动、`HighFrequency` 或新版 `RouteScan` 封禁。
88
- - 自动封禁按 `ExpiresAtUtc` 到期解除。立即解除只能从未被封禁的管理网络,以平台超级管理员进入【系统日志 → 安全防护】调用 `POST /apiengine/mci-system-observability-action`(`Action=UnblockIp`);同一被封出口不能给自己解封。
89
- - 固定可信出口才可精确加入当前服务器匹配 `sys_osclients.SecurityWhitelistIps`。禁止全网段、动态用户 IP 或请求参数自动入白名单,也不要关闭安全防护或全局放大普通阈值。
90
- - 多节点封禁、解封和到期状态必须进入共享 Redis/数据库;本机静态字典只能做缓存。Redis 可用且共享 block 不存在就是权威已解封,节点必须删除本机旧 block,禁止把旧状态回写复活;Redis 不可用时才允许本机降级。验收要让同一出口分别命中至少两个 API 节点,覆盖普通阈值、受信读取、伪造 Header、手动解除和自动到期。
91
-
92
- <!-- /microi-progressive:chunk -->
93
- <!-- microi-progressive:chunk id=v8-security-011 sha256=78053ef853bdffb4eaad90354204555d836d67b9a18f2a6c0ac74a0142df2794 -->
94
- ## 10. Jint 运行时升级边界
95
-
96
- 升级 Jint 时必须逐版阅读官方 release notes,并至少验证以下兼容面,不能只以编译通过作为验收:
97
-
98
- - `Engine` 非线程安全;每次执行使用独立 Engine。`setTimeout` 等回调必须在当前请求内由同一 Engine 串行排空后再释放,禁止 `Task.Run` 捕获 Engine 跨线程或在响应后继续执行。需要可靠后台执行时改用 MQ、Job 或 outbox,不把进程内定时器当作持久任务。
99
- - 重复脚本使用有上限的 `Engine.PrepareScript` 缓存;`Prepared<Script>` 可跨 Engine 复用。Promise 使用 `EvaluateAsync` / `UnwrapIfPromiseAsync` 和请求取消令牌,禁止在 ASP.NET 请求线程上使用阻塞的 `UnwrapIfPromise`。
100
- - 内存 MB 转字节前先提升为 `long`,例如 `checked((long)mb * 1024L * 1024L)`;2GB 用 `int` 相乘会溢出并让限制失真。
101
- - Jint 4.14 默认把 CLR 数组改为 `LiveView`,并默认缓存最近对象包装器。Microi 为兼容历史脚本显式使用 `ArrayConversionMode.Copy + CacheRecentObjectWrappers=false`;若以后切到 LiveView,必须覆盖宿主数组被 JS 修改、固定长度 push/pop 报错、`Array.isArray=false` 和重复读取身份缓存测试。
102
- - 引擎约束必须在平台宿主对象注入完成、用户脚本执行前 `Constraints.Reset()`;同时覆盖超时、语句数、递归、内存、Promise 取消及 CLR 宿主边界返回后的再次检查。
103
-
104
- <!-- /microi-progressive:chunk -->
105
- <!-- microi-progressive:chunk id=v8-security-012 sha256=f7ac9ee1702759fbf5b256ef7b7069ebce75cb845b59786d4eab928335001bf6 -->
106
- ## 安全检查清单
107
-
108
- - [ ] 所有数据库查询使用参数化(`_Where` 或 `@p0`)
109
- - [ ] 把 Token 认证与表/菜单/操作授权分开;列表/写入显式菜单严格精确校验,历史唯一详情只校验同表已授权菜单访问权
110
- - [ ] 当前表前端 facade 自动注入真实菜单,跨表不借用主菜单;可信后端 V8 由服务端标记且不要求菜单
111
- - [ ] 平台表按管理员专用、只读委托、按角色管理三级执行;全部拒绝匿名,Import/Export 必须携带真实菜单并有专项权限
112
- - [ ] 菜单 `SqlWhere` / `SqlJoin` 覆盖真实列表、计数和导出查询;详情只校验同表菜单访问;主表新增/修改/删除/导入只按专项操作权限,不把查询范围带入写 SQL;行级写业务限制由后端 V8/接口引擎校验
113
- - [ ] 授权缓存按租户使用 Redis `epoch` 和用户级快照;冷加载读主库,权限变更递增 `epoch`
114
- - [ ] 关键操作校验 `V8.CurrentUser` 权限
115
- - [ ] 涉及数据修改的接口校验请求参数合法性
116
- - [ ] 敏感数据(手机号、身份证等)脱敏返回
117
- - [ ] 密码只走平台认证/重置流程;禁止MD5/SHA直接存储,后端使用带盐自适应密码哈希
118
- - [ ] 可逆业务秘密只在后端加解密;列表掩码、独立授权显示、no-store 且审计不含明文
119
- - [ ] 新登录/SSO/Passkey/人脸入口最终签发 DiyToken,不并行创建第二套权限体系
120
- - [ ] 敏感操作票据由后端重算 ActionHash 后原子消费,不能相信前端验证成功布尔值
121
- - [ ] 写操作有防重复提交机制
122
- - [ ] 关键操作写审计日志
123
- - [ ] catch 块不暴露内部错误给前端
124
- - [ ] 外部数据库连接串不来自普通请求、不回显,DbKey 无重复且不占用 V8.Dbs 保留名称
125
- - [ ] 外部附件管理入口硬校验 `Level >= 9999`、显式确认、来源脱敏,流式迁移并按源附件 Id 幂等回读
126
- - [ ] Jint 升级覆盖 Prepared 缓存、非阻塞 Promise、long 内存换算、数组互操作兼容和同线程定时器生命周期
127
-
128
- ### 复盘:管理员设计器和升级任务的嵌套 FormEngine 写入被误判
129
-
130
- - 触发场景:`Level=9999` 管理员在表单设计器保存时,外层 `UptFormData`、内部 `UptDiyFieldList` 或 `AddDiyField` 返回 `NoAuth`;无 HTTP 用户的升级任务写 `sys_apiengine/sys_menu/diy_field` 也被拒绝。
131
- - 根因:Redis 保留了旧结构的授权快照,新字段反序列化为 `0/false`;同时更新前旧记录读取或动态新增字段把已校验上下文降成裸 `JObject` / 匿名参数,丢失管理员或可信服务端来源。批量字段保存若逐字段调用完整 CRUD,还会把授权、V8 和缓存工作放大 N 倍。
132
- - 通用规则:授权快照使用独立契约版本;内部嵌套调用必须显式传递原始客户端管理员上下文,或由真正的服务端任务构造不可伪造的强类型可信参数,不能依赖 `_InvokeType` 或 CLR/JObject 猜测。
133
- - 自动化检查:预置缺少新字段的旧 Redis 快照后验证新版本 Key 不命中;分别覆盖管理员设计器批量字段保存/新增字段、普通用户直接写管理员专用表被拒绝、只读委托表写入被拒绝、`mic_print` 有权读取成功、升级程序可信写入成功,以及 HTTP JSON 伪造可信字段仍失败。
134
-
135
- <!-- /microi-progressive:chunk -->
136
- <!-- microi-progressive:chunk id=v8-security-013 sha256=809cd12c1b5fbba76a0b09ebbddf5d2e34189d26ee510c285389294c35b91176 -->
137
- ## 浏览器访问密钥
138
-
139
- 固定看板、电视和信息屏免输入帐号密码时,使用平台 `mci_user_access_key`,禁止自行在接口引擎中保存明文 Secret,也禁止把长期登录 Token 拼进 URL。
140
-
141
- - 一个帐号可有多个密钥;每个密钥独立名称、到期时间(90天/自定义/永久)、范围、使用审计和吊销状态。永久密钥必须可单独吊销并建议定期人工轮换。
142
- - 密钥格式固定为 `microi_ak_<48-bit公开前缀>.<128-bit随机秘密>`,当前总长度 41 个字符;只保存完整密钥的 SHA-256 哈希,明文只在创建时返回一次。日志、MongoDB、Redis、异常和回答中不得出现完整密钥。
143
- - 浏览器启动链接使用 `{Microi.Client前端WebBase}/?OsClient={租户Key}#/access-login?access_key={密钥}&redirect={encodeURIComponent后的站内Hash路由}`。例如目标路由 `/mic/data-dashboard/preview/01KK988A0YPHKAM8SF216917HX` 编码后是 `redirect=%2Fmic%2Fdata-dashboard%2Fpreview%2F01KK988A0YPHKAM8SF216917HX`。前端域名不能误用 API Server;目标路由必须以 `/` 开头并位于密钥允许页面范围内。
144
- - 固定电视/看板应保存完整 `/access-login` 链接作为浏览器开机主页或受控书签,不能只保存兑换后的预览页。`access_key` 位于 Hash 中,前端解析后立即 `history.replaceState` 清除;地址栏随后不含密钥是正常安全行为,禁止给目标页重复追加密钥或引入 `permanent=1/keep_login=1` 等客户端寿命参数。永久只描述密钥记录不计划到期;短期受限 Token 正常轮换,会话丢失时重新打开启动链接再次兑换。后端兑换只接受 JSON Body。
145
- - 兑换得到短期 `_ClientType=AccessKey` Token。JWT 只保存 `MicroiAccessKeyId`,权限范围从共享数据库/Redis实时加载,不能把范围写进共享 `CurrentToken.CurrentUser`。
146
- - 密钥权限只能收窄:帐号实时角色/菜单/行范围与 `Scopes + AllowedRoutes + AllowedTableNames + AllowedApiEngineKeys + AllowedDataSourceKeys` 取交集。检查必须位于管理员快捷放行之前。
147
- - 默认只允许 `page:open + form:read`;`form:write/form:export/file:read/api-engine:run/data-source:run` 必须显式启用。`AllowedRoutes` 和 `AllowedTableNames` 可以使用单独值 `*` 表示“全部目标帐号已授权资源”,但检查仍必须位于管理员快捷放行之前并继续执行帐号菜单、表单、部门和行权限;旧 UI 误存的路由值 `/*` 只作为该通配值的兼容别名。`AllowedApiEngineKeys` 和 `AllowedDataSourceKeys` 必须是准确白名单,禁止 `*`。
148
- - API 放行必须使用按 capability 分类的运行时矩阵,不能靠零散补一个报错路径:页面范围为 `*` 且具有 `page:open` 时才允许 `SysMenu/GetSysMenuStep`;指定页面密钥不得读取完整菜单树。只允许会话启动、页面元数据、表单 CRUD/导出、本人后台任务和本人终端信息等明确运行面;显示密码、密钥管理、菜单/表/字段设计、索引、缓存、服务器、其它终端管理等控制面保持拒绝。
149
- - FormEngine 通过 action filter 对模型绑定后的 `FormEngineKey/TableName/TableId/TableIds` 逐项校验,并单独识别 `ModuleEngineKey/_ModuleEngineKey/_SysMenuId/SysMenuId`。`AllowedTableNames` 在共享数据库回源时派生为 `AllowedTableIds + AllowedFieldIds + AllowedMenuReferences`;菜单引用只收集 `DiyTableId` 位于允许范围内的 `sys_menu.Id/ModuleEngineKey`,全部放进带契约版本的短 TTL Redis 运行时缓存。解析失败必须 fail closed。这样只传表 Id 的元数据接口、只传 `_FieldId/FieldIds` 的字段 SQL/批量下拉数据接口,以及只传菜单 Id 的标准列表请求,都不能绕过表名白名单或被误拒绝。
150
- - FormEngine 的动态友好路由(如 `GetTableData-{table-key}`、`Get-TableData-{table-key}`、`GetFormData-{table-key}` 及写入别名)必须在 API capability 鉴权前归一化。动态路由转换器与访问密钥鉴权必须复用同一个别名解析器,禁止各维护一份前缀清单;归一化只决定所需 scope,URL 后缀还必须与模型绑定后的 `FormEngineKey/TableId/ModuleEngineKey/_SysMenuId` 之一规范化一致,并再次校验准确表或菜单引用。空 Key、前后缀不一致、额外路径段和相似前缀必须拒绝。
151
- - `ApiEngineController` 的 Run 系列即使标记了 `[AllowAnonymous]`,检测到访问密钥会话后也必须解析实际命中的引擎模型并校验准确 `ApiEngineKey`;数据源运行和后台接口任务同样校验准确 Key。禁止只在 MVC 授权过滤器中检查粗粒度路径,因为匿名兼容入口会跳过该过滤器。
152
- - 自动登录 URL 必须携带当前 `OsClient`;前端进入 `/access-login` 时先清除 Hash 中的密钥,再用 JSON Body 兑换,并设置有限超时。禁止等待与兑换无关的 SSO 初始化导致无限加载。
153
- - 管理操作只允许普通登录会话的本人或管理员;访问密钥会话不能创建或吊销密钥。系统账号中的管理入口必须由 `sys_menu.MoreBtns` 动态配置,并通过通用 `V8.OpenDialog` 打开预注册的 `UserAccessKeyPanel`;不得新增业务专用 `V8.OpenUserAccessKeys`,也不得在通用表格/卡片模板中按表名硬编码。按钮显隐不能代替后端逐次鉴权。
154
- - 多节点共享 Redis 只作为短 TTL 缓存和限流;数据库是事实源,吊销主动清除缓存。不得使用 `static` 字典、本机文件或本地定时器保存密钥状态。
155
- - 对外仍要求 HTTPS。固定终端使用独立只读帐号,不能用超级管理员帐号创建看板密钥。
156
-
157
- 验收至少覆盖:明文只返回一次、错误密钥固定时间比较、过期/吊销/停用帐号失败、指定页面成功而其它路由失败、全部页面可加载 `GetSysMenuStep`、标准与动态 `GetTableData/GetFormData` 路由均可读取允许表、仅传绑定菜单 Id 的 `ModuleEngineKey` 动态列表成功、动态写路由仍要求 `form:write`、空 Key/前后缀不一致/相似前缀/额外路径段失败、允许表名及对应表 Id/菜单 Id 成功而其它资源失败、FormEngine 设计接口仍拒绝、接口/数据源 Key 精确限制且动态/后台入口不能绕过、普通帐号权限变化即时收窄、两个 API 节点吊销一致生效。
158
- <!-- /microi-progressive:chunk -->
1
+ # v8-security 详细参考 2
2
+
3
+ > 按需读取;本文件由 SKILL.md 的原章节无损拆分。
4
+
5
+ <!-- microi-progressive:chunk id=v8-security-008 sha256=6e0b7de3cd72cc030c93566c03ddf2191af6163d378e5ec8a40828eee9873477 -->
6
+ ## 7. 日志记录
7
+
8
+ 关键操作必须记录审计日志:
9
+
10
+ ```javascript
11
+ // 记录敏感操作
12
+ V8.Method.AddSysLog({
13
+ Title: '删除用户',
14
+ Content: JSON.stringify({
15
+ OperatorId: V8.CurrentUser.Id,
16
+ OperatorName: V8.CurrentUser.Name,
17
+ TargetId: V8.Param.userId,
18
+ Time: DateNow('yyyy-MM-dd HH:mm:ss')
19
+ }),
20
+ Type: '安全审计',
21
+ Level: 2
22
+ });
23
+ ```
24
+
25
+ ### 管理员吊销用户全部登录态
26
+
27
+ 需要让某个用户所有终端立即退出时,接口引擎必须调用平台统一能力,不要只删除前端 Token,也不要只修改用户状态:
28
+
29
+ ```javascript
30
+ if (!V8.CurrentUser || Number(V8.CurrentUser.Level || 0) < 9999) {
31
+ return { Code: 0, Msg: '仅系统管理员可执行此操作' };
32
+ }
33
+
34
+ var clearResult = V8.Method.ClearUserLoginInfo(V8.Param.UserId, V8.OsClient);
35
+ if (clearResult.Code != 1) {
36
+ return clearResult;
37
+ }
38
+ ```
39
+
40
+ - `ClearUserLoginInfo` 会删除该用户 Redis 中的全部终端 Token,旧 Token 随即失效且不能继续以旧换新。
41
+ - 已建立实时连接的终端会收到 `ReceiveForceLogout` 并立即退出;没有实时连接的终端在下一次请求时收到 Token 失效。
42
+ - “禁用用户”必须先吊销全部登录态,再把 `sys_user.State` 更新为 `0`,并记录安全审计日志。
43
+ - 接口引擎和底层方法都必须校验管理员权限、目标用户 Id 和租户边界,禁止跨租户吊销。
44
+
45
+ <!-- /microi-progressive:chunk -->
46
+ <!-- microi-progressive:chunk id=v8-security-009 sha256=b7a65ce2785a6a3d02dc1bc08c16c5ae03e38aa199d4bc204abe5978057f1ea1 -->
47
+ ## 8. 错误处理
48
+
49
+ 不要把内部错误信息暴露给前端:
50
+
51
+ ```javascript
52
+ try {
53
+ var result = V8.Db.FromSql('SELECT * FROM t WHERE Id = @p0')
54
+ .AddInParameter("@p0", V8.Param.id)
55
+ .ToArray();
56
+ return { Code: 1, Data: result };
57
+ } catch (ex) {
58
+ // 内部日志使用追踪号和必要的非敏感字段;不要记录完整V8.Param
59
+ var traceId = V8.Method.NewUlid();
60
+ console.error('查询失败 traceId=' + traceId + ' error=' + ex.message);
61
+ // 返回给前端的信息不含内部细节
62
+ return { Code: 0, Msg: '查询失败,请稍后重试', DataAppend: { TraceId: traceId } };
63
+ }
64
+ ```
65
+
66
+ <!-- /microi-progressive:chunk -->
67
+ <!-- microi-progressive:chunk id=v8-security-010 sha256=4b68e2730cc6ac2ba8eeb4458c71e9ee157b9ac8054dcab364f364b2e0bd1c05 -->
68
+ ## 9. Token、终端会话与租户隔离
69
+
70
+ 开发 Web、H5、UniApp、小程序、App、VS Code 或 MCP 客户端时,必须同时遵守 `microi-frontend-sdk/SKILL.md` 的 Token 协议:登录传 `_ClientType`,请求头传稳定 `did`,每次响应接收新的 `authorization`,并在浏览器/应用恢复前台时检查续签。
71
+
72
+ - PC 默认使用 `SessionAuthTimeout` 分钟策略;移动端、VS Code、MCP 默认使用 `AccessTokenLifetime` 天策略。不要在前端自行扩大服务端有效期。
73
+ - Token 的 `OsClient` 必须与当前请求租户一致。收到 `TenantMismatch` 时立即停止请求,不能自动把 Token 复制到另一个租户。
74
+ - 收到 `JwtExpired`、`SessionExpired`、`SessionMissing`、`AuthVersionChanged` 时清理当前连接的 Token;多服务器或多租户客户端只能清理受影响的连接,不能全局退出其它连接。
75
+ - 收到 `TokenReplaced` 时先检查同一终端是否已有新 Token,避免并发旧响应误清新登录态。
76
+ - 用户提示可以显示过期时长、终端类型和租户 Key,但日志、Toast、URL、截图禁止输出完整 Token。
77
+
78
+ ### IP 高频拦截、受信 VS Code 独立阈值与解除
79
+
80
+ - `DataAppend.SecurityBlocked=true` 是服务端已可达但当前 IP 被临时拦截,不是网络断开。前端必须展示原始 `Msg`、`Reason`、`ExpiresAtUtc`、IP 和解除建议;不能把它转换成“后端 API 服务暂时不可用”。直接返回该结果的安全中间件必须在 CORS 之后。
81
+ - 普通访问默认阈值为 10 秒 600 请求/120 异常。VS Code 多服务器源码拉取不能通过减少并发或请求量规避;符合条件的只读 V8Debug `Get/List` 使用独立桶,默认 10 秒 6000 请求/1200 异常。
82
+ - 受信判断必须同时满足:服务端共享登录态确认 `Level >= 9999`、请求 Token 是活动 `ClientType=VSCode` Token、请求 `did` 与该 Token 保存的 Did 完全一致、路由为只读 `/api/V8Debug/Get*` 或 `/api/V8Debug/List*`。自报 `ClientType`、User-Agent、`X-User-Level`、单独伪造 did 都不可信;Update/Create/Execute/Upload/Finalize 和 FormEngine 写入不放宽。
83
+ - 普通请求的计数 scope 固定为当前 API 主运行实例,不能使用请求方可控的 `OsClient` Query/Header 选择 Redis 桶;只有已通过上述联合校验的 VS Code profile 才能使用活动 Token 服务端绑定的租户 scope。测试必须覆盖轮换两个真实租户 Key 仍落入同一普通桶。
84
+ - SecurityGuard 只读取 `Connection.RemoteIpAddress`,不得直接解析 `X-Forwarded-For`/`X-Real-IP`。容器运行时可自动信任当前容器路由表实际发现的 RFC1918/ULA 私有默认网关**精确 IP**,用于宿主 Nginx 经 Docker 发布端口转发的最后一跳;不得自动信任公网网关或任意私有网段。其它代理只信任主租户 SaaS 引擎【后端运行配置】的 `BackendForwardedKnownProxies` 精确 IP 和 `BackendForwardedKnownNetworks` 受控 CIDR;禁止使用环境变量、自定义 `appsettings` 节点、`0.0.0.0/0` 或 `::/0`。历史 `SecurityRespectForwardedHeaders` 字段不能建立 Header 信任。该宿主配置变更需滚动重启节点,测试必须覆盖容器网关把 XFF 投影为真实 IP,以及公网 Remote IP 携带伪造 `X-Forwarded-For: 127.0.0.1` 时仍识别公网 IP。
85
+ - `UseForwardedHeaders` 后若 Remote IP 仍是自动发现的精确容器网关,表示代理未提供可验证的客户端地址;该请求不得进入按 IP 自动封禁,否则任一用户可导致全站误封。此降级不跳过后续全局请求压力、内存和业务鉴权,公网或普通私网地址也不适用;运维仍应补齐最后一跳转发头。
86
+ - IP 错误窗口只把未匹配端点的 404/405 作为扫描计数;400/401/403/413/429、5xx、已匹配 Controller 以及 `/api`、`/apiengine` 动态路由的应用级 404/405 只能审计,不能触发自动封禁。请求总量窗口继续作为独立的高频攻击门禁,禁止用服务端故障或正常业务拒绝反向惩罚客户端。
87
+ - 旧版 `HighError`/`TrustedVsCodeHighError` 宽泛错误策略产生的自动封禁属于可识别的失效状态;升级节点应从共享 Redis 和本机缓存幂等退休,不能要求所有租户等待旧 TTL,也不能解除手动、`HighFrequency` 或新版 `RouteScan` 封禁。
88
+ - 自动封禁按 `ExpiresAtUtc` 到期解除。立即解除只能从未被封禁的管理网络,以平台超级管理员进入【系统日志 → 安全防护】调用 `POST /apiengine/mci-system-observability-action`(`Action=UnblockIp`);同一被封出口不能给自己解封。
89
+ - 固定可信出口才可精确加入当前服务器匹配 `sys_osclients.SecurityWhitelistIps`。禁止全网段、动态用户 IP 或请求参数自动入白名单,也不要关闭安全防护或全局放大普通阈值。
90
+ - 多节点封禁、解封和到期状态必须进入共享 Redis/数据库;本机静态字典只能做缓存。Redis 可用且共享 block 不存在就是权威已解封,节点必须删除本机旧 block,禁止把旧状态回写复活;Redis 不可用时才允许本机降级。验收要让同一出口分别命中至少两个 API 节点,覆盖普通阈值、受信读取、伪造 Header、手动解除和自动到期。
91
+
92
+ <!-- /microi-progressive:chunk -->
93
+ <!-- microi-progressive:chunk id=v8-security-011 sha256=78053ef853bdffb4eaad90354204555d836d67b9a18f2a6c0ac74a0142df2794 -->
94
+ ## 10. Jint 运行时升级边界
95
+
96
+ 升级 Jint 时必须逐版阅读官方 release notes,并至少验证以下兼容面,不能只以编译通过作为验收:
97
+
98
+ - `Engine` 非线程安全;每次执行使用独立 Engine。`setTimeout` 等回调必须在当前请求内由同一 Engine 串行排空后再释放,禁止 `Task.Run` 捕获 Engine 跨线程或在响应后继续执行。需要可靠后台执行时改用 MQ、Job 或 outbox,不把进程内定时器当作持久任务。
99
+ - 重复脚本使用有上限的 `Engine.PrepareScript` 缓存;`Prepared<Script>` 可跨 Engine 复用。Promise 使用 `EvaluateAsync` / `UnwrapIfPromiseAsync` 和请求取消令牌,禁止在 ASP.NET 请求线程上使用阻塞的 `UnwrapIfPromise`。
100
+ - 内存 MB 转字节前先提升为 `long`,例如 `checked((long)mb * 1024L * 1024L)`;2GB 用 `int` 相乘会溢出并让限制失真。
101
+ - Jint 4.14 默认把 CLR 数组改为 `LiveView`,并默认缓存最近对象包装器。Microi 为兼容历史脚本显式使用 `ArrayConversionMode.Copy + CacheRecentObjectWrappers=false`;若以后切到 LiveView,必须覆盖宿主数组被 JS 修改、固定长度 push/pop 报错、`Array.isArray=false` 和重复读取身份缓存测试。
102
+ - 引擎约束必须在平台宿主对象注入完成、用户脚本执行前 `Constraints.Reset()`;同时覆盖超时、语句数、递归、内存、Promise 取消及 CLR 宿主边界返回后的再次检查。
103
+
104
+ <!-- /microi-progressive:chunk -->
105
+ <!-- microi-progressive:chunk id=v8-security-012 sha256=f7ac9ee1702759fbf5b256ef7b7069ebce75cb845b59786d4eab928335001bf6 -->
106
+ ## 安全检查清单
107
+
108
+ - [ ] 所有数据库查询使用参数化(`_Where` 或 `@p0`)
109
+ - [ ] 把 Token 认证与表/菜单/操作授权分开;列表/写入显式菜单严格精确校验,历史唯一详情只校验同表已授权菜单访问权
110
+ - [ ] 当前表前端 facade 自动注入真实菜单,跨表不借用主菜单;可信后端 V8 由服务端标记且不要求菜单
111
+ - [ ] 平台表按管理员专用、只读委托、按角色管理三级执行;全部拒绝匿名,Import/Export 必须携带真实菜单并有专项权限
112
+ - [ ] 菜单 `SqlWhere` / `SqlJoin` 覆盖真实列表、计数和导出查询;详情只校验同表菜单访问;主表新增/修改/删除/导入只按专项操作权限,不把查询范围带入写 SQL;行级写业务限制由后端 V8/接口引擎校验
113
+ - [ ] 授权缓存按租户使用 Redis `epoch` 和用户级快照;冷加载读主库,权限变更递增 `epoch`
114
+ - [ ] 关键操作校验 `V8.CurrentUser` 权限
115
+ - [ ] 涉及数据修改的接口校验请求参数合法性
116
+ - [ ] 敏感数据(手机号、身份证等)脱敏返回
117
+ - [ ] 密码只走平台认证/重置流程;禁止MD5/SHA直接存储,后端使用带盐自适应密码哈希
118
+ - [ ] 可逆业务秘密只在后端加解密;列表掩码、独立授权显示、no-store 且审计不含明文
119
+ - [ ] 新登录/SSO/Passkey/人脸入口最终签发 DiyToken,不并行创建第二套权限体系
120
+ - [ ] 敏感操作票据由后端重算 ActionHash 后原子消费,不能相信前端验证成功布尔值
121
+ - [ ] 写操作有防重复提交机制
122
+ - [ ] 关键操作写审计日志
123
+ - [ ] catch 块不暴露内部错误给前端
124
+ - [ ] 外部数据库连接串不来自普通请求、不回显,DbKey 无重复且不占用 V8.Dbs 保留名称
125
+ - [ ] 外部附件管理入口硬校验 `Level >= 9999`、显式确认、来源脱敏,流式迁移并按源附件 Id 幂等回读
126
+ - [ ] Jint 升级覆盖 Prepared 缓存、非阻塞 Promise、long 内存换算、数组互操作兼容和同线程定时器生命周期
127
+
128
+ ### 复盘:管理员设计器和升级任务的嵌套 FormEngine 写入被误判
129
+
130
+ - 触发场景:`Level=9999` 管理员在表单设计器保存时,外层 `UptFormData`、内部 `UptDiyFieldList` 或 `AddDiyField` 返回 `NoAuth`;无 HTTP 用户的升级任务写 `sys_apiengine/sys_menu/diy_field` 也被拒绝。
131
+ - 根因:Redis 保留了旧结构的授权快照,新字段反序列化为 `0/false`;同时更新前旧记录读取或动态新增字段把已校验上下文降成裸 `JObject` / 匿名参数,丢失管理员或可信服务端来源。批量字段保存若逐字段调用完整 CRUD,还会把授权、V8 和缓存工作放大 N 倍。
132
+ - 通用规则:授权快照使用独立契约版本;内部嵌套调用必须显式传递原始客户端管理员上下文,或由真正的服务端任务构造不可伪造的强类型可信参数,不能依赖 `_InvokeType` 或 CLR/JObject 猜测。
133
+ - 自动化检查:预置缺少新字段的旧 Redis 快照后验证新版本 Key 不命中;分别覆盖管理员设计器批量字段保存/新增字段、普通用户直接写管理员专用表被拒绝、只读委托表写入被拒绝、`mic_print` 有权读取成功、升级程序可信写入成功,以及 HTTP JSON 伪造可信字段仍失败。
134
+
135
+ <!-- /microi-progressive:chunk -->
136
+ <!-- microi-progressive:chunk id=v8-security-013 sha256=809cd12c1b5fbba76a0b09ebbddf5d2e34189d26ee510c285389294c35b91176 -->
137
+ ## 浏览器访问密钥
138
+
139
+ 固定看板、电视和信息屏免输入帐号密码时,使用平台 `mci_user_access_key`,禁止自行在接口引擎中保存明文 Secret,也禁止把长期登录 Token 拼进 URL。
140
+
141
+ - 一个帐号可有多个密钥;每个密钥独立名称、到期时间(90天/自定义/永久)、范围、使用审计和吊销状态。永久密钥必须可单独吊销并建议定期人工轮换。
142
+ - 密钥格式固定为 `microi_ak_<48-bit公开前缀>.<128-bit随机秘密>`,当前总长度 41 个字符;只保存完整密钥的 SHA-256 哈希,明文只在创建时返回一次。日志、MongoDB、Redis、异常和回答中不得出现完整密钥。
143
+ - 浏览器启动链接使用 `{Microi.Client前端WebBase}/?OsClient={租户Key}#/access-login?access_key={密钥}&redirect={encodeURIComponent后的站内Hash路由}`。例如目标路由 `/mic/data-dashboard/preview/01KK988A0YPHKAM8SF216917HX` 编码后是 `redirect=%2Fmic%2Fdata-dashboard%2Fpreview%2F01KK988A0YPHKAM8SF216917HX`。前端域名不能误用 API Server;目标路由必须以 `/` 开头并位于密钥允许页面范围内。
144
+ - 固定电视/看板应保存完整 `/access-login` 链接作为浏览器开机主页或受控书签,不能只保存兑换后的预览页。`access_key` 位于 Hash 中,前端解析后立即 `history.replaceState` 清除;地址栏随后不含密钥是正常安全行为,禁止给目标页重复追加密钥或引入 `permanent=1/keep_login=1` 等客户端寿命参数。永久只描述密钥记录不计划到期;短期受限 Token 正常轮换,会话丢失时重新打开启动链接再次兑换。后端兑换只接受 JSON Body。
145
+ - 兑换得到短期 `_ClientType=AccessKey` Token。JWT 只保存 `MicroiAccessKeyId`,权限范围从共享数据库/Redis实时加载,不能把范围写进共享 `CurrentToken.CurrentUser`。
146
+ - 密钥权限只能收窄:帐号实时角色/菜单/行范围与 `Scopes + AllowedRoutes + AllowedTableNames + AllowedApiEngineKeys + AllowedDataSourceKeys` 取交集。检查必须位于管理员快捷放行之前。
147
+ - 默认只允许 `page:open + form:read`;`form:write/form:export/file:read/api-engine:run/data-source:run` 必须显式启用。`AllowedRoutes` 和 `AllowedTableNames` 可以使用单独值 `*` 表示“全部目标帐号已授权资源”,但检查仍必须位于管理员快捷放行之前并继续执行帐号菜单、表单、部门和行权限;旧 UI 误存的路由值 `/*` 只作为该通配值的兼容别名。`AllowedApiEngineKeys` 和 `AllowedDataSourceKeys` 必须是准确白名单,禁止 `*`。
148
+ - API 放行必须使用按 capability 分类的运行时矩阵,不能靠零散补一个报错路径:页面范围为 `*` 且具有 `page:open` 时才允许 `SysMenu/GetSysMenuStep`;指定页面密钥不得读取完整菜单树。只允许会话启动、页面元数据、表单 CRUD/导出、本人后台任务和本人终端信息等明确运行面;显示密码、密钥管理、菜单/表/字段设计、索引、缓存、服务器、其它终端管理等控制面保持拒绝。
149
+ - FormEngine 通过 action filter 对模型绑定后的 `FormEngineKey/TableName/TableId/TableIds` 逐项校验,并单独识别 `ModuleEngineKey/_ModuleEngineKey/_SysMenuId/SysMenuId`。`AllowedTableNames` 在共享数据库回源时派生为 `AllowedTableIds + AllowedFieldIds + AllowedMenuReferences`;菜单引用只收集 `DiyTableId` 位于允许范围内的 `sys_menu.Id/ModuleEngineKey`,全部放进带契约版本的短 TTL Redis 运行时缓存。解析失败必须 fail closed。这样只传表 Id 的元数据接口、只传 `_FieldId/FieldIds` 的字段 SQL/批量下拉数据接口,以及只传菜单 Id 的标准列表请求,都不能绕过表名白名单或被误拒绝。
150
+ - FormEngine 的动态友好路由(如 `GetTableData-{table-key}`、`Get-TableData-{table-key}`、`GetFormData-{table-key}` 及写入别名)必须在 API capability 鉴权前归一化。动态路由转换器与访问密钥鉴权必须复用同一个别名解析器,禁止各维护一份前缀清单;归一化只决定所需 scope,URL 后缀还必须与模型绑定后的 `FormEngineKey/TableId/ModuleEngineKey/_SysMenuId` 之一规范化一致,并再次校验准确表或菜单引用。空 Key、前后缀不一致、额外路径段和相似前缀必须拒绝。
151
+ - `ApiEngineController` 的 Run 系列即使标记了 `[AllowAnonymous]`,检测到访问密钥会话后也必须解析实际命中的引擎模型并校验准确 `ApiEngineKey`;数据源运行和后台接口任务同样校验准确 Key。禁止只在 MVC 授权过滤器中检查粗粒度路径,因为匿名兼容入口会跳过该过滤器。
152
+ - 自动登录 URL 必须携带当前 `OsClient`;前端进入 `/access-login` 时先清除 Hash 中的密钥,再用 JSON Body 兑换,并设置有限超时。禁止等待与兑换无关的 SSO 初始化导致无限加载。
153
+ - 管理操作只允许普通登录会话的本人或管理员;访问密钥会话不能创建或吊销密钥。系统账号中的管理入口必须由 `sys_menu.MoreBtns` 动态配置,并通过通用 `V8.OpenDialog` 打开预注册的 `UserAccessKeyPanel`;不得新增业务专用 `V8.OpenUserAccessKeys`,也不得在通用表格/卡片模板中按表名硬编码。按钮显隐不能代替后端逐次鉴权。
154
+ - 多节点共享 Redis 只作为短 TTL 缓存和限流;数据库是事实源,吊销主动清除缓存。不得使用 `static` 字典、本机文件或本地定时器保存密钥状态。
155
+ - 对外仍要求 HTTPS。固定终端使用独立只读帐号,不能用超级管理员帐号创建看板密钥。
156
+
157
+ 验收至少覆盖:明文只返回一次、错误密钥固定时间比较、过期/吊销/停用帐号失败、指定页面成功而其它路由失败、全部页面可加载 `GetSysMenuStep`、标准与动态 `GetTableData/GetFormData` 路由均可读取允许表、仅传绑定菜单 Id 的 `ModuleEngineKey` 动态列表成功、动态写路由仍要求 `form:write`、空 Key/前后缀不一致/相似前缀/额外路径段失败、允许表名及对应表 Id/菜单 Id 成功而其它资源失败、FormEngine 设计接口仍拒绝、接口/数据源 Key 精确限制且动态/后台入口不能绕过、普通帐号权限变化即时收窄、两个 API 节点吊销一致生效。
158
+ <!-- /microi-progressive:chunk -->