@microi.net/cli 5.8.5 → 5.8.7
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/.codebuddy-plugin/marketplace.json +2 -2
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.workbuddy-plugin/marketplace.json +2 -2
- package/.workbuddy-plugin/plugin.json +1 -1
- package/LICENSE +21 -21
- package/README.md +71 -71
- package/assets/build-meta.json +7 -7
- package/assets/feature-matrix.json +138 -138
- package/assets/logo.svg +4 -4
- package/cordis.patch.yml +1 -1
- package/package.json +1 -1
- package/scripts/mcp-codex-stdio-adapter.js +0 -0
- package/scripts/mcp-server.js +1 -1
- package/scripts/microi-cli.js +66 -65
- package/scripts/microi-codex-broker.js +450 -450
- package/scripts/microi-codex-router.js +618 -618
- package/scripts/microi-skills.meta.json +384 -384
- package/skills/.microi-skills-version.json +2 -2
- package/skills/.progressive-disclosure-manifest.json +21 -21
- package/skills/README.md +287 -287
- package/skills/ai-engine/SKILL.md +269 -265
- package/skills/ai-engine/agents/openai.yaml +4 -4
- package/skills/ai-engine/references/ai-employees.md +48 -48
- package/skills/ai-engine/references/self-hosted-digital-human.md +59 -59
- package/skills/ai-platform-governance/SKILL.md +177 -177
- package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -190
- package/skills/app-store/SKILL.md +525 -525
- package/skills/app-store/agents/openai.yaml +4 -4
- package/skills/business-blueprint/SKILL.md +193 -193
- package/skills/datasource-engine/SKILL.md +93 -93
- package/skills/datasource-engine/agents/openai.yaml +4 -4
- package/skills/dos-orm/SKILL.md +97 -95
- package/skills/dos-orm/references/api-reference.md +229 -229
- package/skills/email-engine/SKILL.md +81 -81
- package/skills/email-engine/references/v8-email.md +34 -34
- package/skills/job-engine/SKILL.md +176 -176
- package/skills/job-engine/agents/openai.yaml +4 -4
- package/skills/message-notification/SKILL.md +156 -156
- package/skills/message-notification/agents/openai.yaml +5 -5
- package/skills/message-notification/references/contracts.md +102 -102
- package/skills/microi/SKILL.md +14 -14
- package/skills/microi-ai-app-auth.js +652 -652
- package/skills/microi-ai-application/SKILL.md +115 -115
- package/skills/microi-ai-application/agents/openai.yaml +4 -4
- package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
- package/skills/microi-client-frontend/SKILL.md +246 -244
- 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
- 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
- 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
- package/skills/microi-codex/SKILL.md +102 -100
- package/skills/microi-codex-installer/SKILL.md +231 -231
- package/skills/microi-codex-installer/agents/openai.yaml +7 -7
- package/skills/microi-datasource-mapping/SKILL.md +122 -122
- package/skills/microi-db-schema/SKILL.md +175 -175
- package/skills/microi-db-schema/agents/openai.yaml +4 -4
- package/skills/microi-db-schema/references/core-tables.md +695 -695
- package/skills/microi-db-schema/references/form-component-options.md +256 -256
- package/skills/microi-db-schema/references/schema-overview.md +202 -202
- package/skills/microi-db-schema/references/schema.md +646 -646
- package/skills/microi-db-schema/references/table-catalog.md +1599 -1599
- package/skills/microi-deployment/SKILL.md +222 -220
- package/skills/microi-deployment/references/deployment-matrix.md +109 -109
- package/skills/microi-docs-coverage/SKILL.md +133 -133
- package/skills/microi-docs-coverage/references/capability-map.md +91 -91
- package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
- package/skills/microi-form-engine/SKILL.md +333 -333
- package/skills/microi-form-engine/references/component-catalog.md +218 -218
- package/skills/microi-form-engine/references/data-source-events.md +124 -124
- package/skills/microi-form-layout/SKILL.md +205 -205
- 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
- package/skills/microi-frontend-sdk/SKILL.md +194 -194
- 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
- package/skills/microi-left-right-layout/SKILL.md +141 -141
- package/skills/microi-microservice/SKILL.md +328 -326
- package/skills/microi-microservice/references/runtime-delivery.md +278 -278
- package/skills/microi-mobile-app-quality/SKILL.md +185 -185
- 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
- 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
- package/skills/microi-solution-quotation/SKILL.md +78 -78
- package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
- package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
- package/skills/microi-sso/SKILL.md +96 -90
- package/skills/microi-sso/references/acceptance.md +49 -49
- package/skills/microi-sso/references/configuration-and-security.md +53 -53
- package/skills/microi-sso/references/inbound.md +53 -53
- package/skills/microi-sso/references/outbound.md +39 -39
- package/skills/microi-system-delivery/SKILL.md +137 -137
- 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
- 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 +217 -217
- package/skills/microi-ui/SKILL.md +192 -192
- 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
- package/skills/microi-uniapp-frontend/SKILL.md +193 -193
- 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
- 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
- package/skills/microi.v8.js +1921 -1921
- package/skills/module-engine/SKILL.md +255 -255
- package/skills/module-engine/references/module-config.md +204 -204
- package/skills/ocr-engine/SKILL.md +113 -113
- package/skills/ocr-engine/agents/openai.yaml +4 -4
- package/skills/page-engine/SKILL.md +206 -206
- package/skills/page-engine/examples/compact-dashboard.json +1444 -1444
- 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
- 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
- package/skills/performance-testing/SKILL.md +221 -221
- package/skills/playwright-e2e/SKILL.md +196 -196
- 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
- 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
- package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -221
- package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +115 -115
- package/skills/print-engine/SKILL.md +259 -259
- package/skills/production-readonly-audit/SKILL.md +41 -41
- package/skills/report-engine/SKILL.md +71 -71
- package/skills/report-engine/agents/openai.yaml +4 -4
- package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
- package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
- package/skills/scripts/sync-embedded-skills.mjs +46 -46
- package/skills/scripts/validate-progressive-disclosure.mjs +57 -57
- package/skills/search-engine/SKILL.md +75 -75
- package/skills/search-engine/agents/openai.yaml +4 -4
- package/skills/spider-engine/SKILL.md +190 -190
- package/skills/system-observability/SKILL.md +249 -246
- package/skills/system-observability/references/memory-incident-triage.md +77 -77
- package/skills/translate-engine/SKILL.md +140 -140
- package/skills/translate-engine/agents/openai.yaml +4 -4
- package/skills/ui-design/SKILL.md +223 -223
- package/skills/ui-design/assets/pattern-showcase/app.js +54 -54
- package/skills/ui-design/assets/pattern-showcase/index.html +163 -163
- package/skills/ui-design/assets/pattern-showcase/styles.css +311 -311
- package/skills/ui-design/assets/templates/MCI-DESIGN.md +206 -206
- package/skills/ui-design/references/design-pattern-library.md +184 -184
- package/skills/ui-design/references/mci-design-contract.md +163 -163
- package/skills/ui-design/references/motion-and-media.md +78 -78
- package/skills/ui-design/references/product-flow-recipes.md +94 -94
- 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
- package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +164 -164
- 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
- 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
- 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
- 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
- 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
- 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 +142 -142
- package/skills/uniapp-mall-assets/SKILL.md +176 -176
- package/skills/unity-integration/SKILL.md +171 -171
- package/skills/unity-integration/agents/openai.yaml +4 -4
- package/skills/unity-integration/references/ai-app-delivery.md +119 -119
- package/skills/unity-integration/references/sdk-api.md +82 -82
- package/skills/unity-integration/references/toolbox-migration.md +66 -66
- package/skills/unity-integration/references/webgl-hosting.md +57 -57
- package/skills/v8-api-config/SKILL.md +388 -388
- package/skills/v8-cache-pattern/SKILL.md +312 -312
- package/skills/v8-crud-api/SKILL.md +178 -178
- 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
- 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
- package/skills/v8-debugging/SKILL.md +284 -284
- package/skills/v8-explorer-tree/SKILL.md +228 -228
- package/skills/v8-export-import/SKILL.md +219 -219
- 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
- package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -202
- 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
- package/skills/v8-file-upload/SKILL.md +284 -284
- 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 +263 -263
- 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 +161 -161
- package/skills/v8-formengine-http/SKILL.md +238 -238
- package/skills/v8-frontend-events/SKILL.md +180 -180
- package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
- package/skills/v8-frontend-events/references/bluetooth-print.md +258 -258
- package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -219
- package/skills/v8-http-integration/SKILL.md +182 -182
- package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -220
- 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
- package/skills/v8-image-processing/SKILL.md +190 -190
- package/skills/v8-image-processing/agents/openai.yaml +4 -4
- package/skills/v8-image-processing/references/api-reference.md +623 -623
- package/skills/v8-menu-buttons/SKILL.md +186 -186
- 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
- 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
- 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
- package/skills/v8-mongodb/SKILL.md +200 -200
- package/skills/v8-mq-mqtt/SKILL.md +176 -176
- package/skills/v8-mq-mqtt/references/mqtt-production.md +342 -342
- package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -181
- package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
- package/skills/v8-saas-multi-tenant/SKILL.md +305 -305
- package/skills/v8-security/SKILL.md +210 -210
- package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +200 -200
- package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +160 -160
- package/skills/v8-sql-query/SKILL.md +302 -302
- package/skills/v8-table-event/SKILL.md +176 -176
- 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 +216 -216
- 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
- package/skills/v8-tcp-integration/SKILL.md +147 -147
- package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
- package/skills/v8-template-engine/SKILL.md +167 -167
- package/skills/v8-utilities/SKILL.md +104 -104
- package/skills/v8-utilities/references/client-api-index.md +143 -143
- package/skills/v8-utilities/references/platform-http-routes.md +83 -83
- package/skills/v8-utilities/references/server-api-index.md +188 -188
- package/skills/v8-workflow/SKILL.md +252 -252
- 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
- package/skills/v8-workflow/references/workflow-configuration.md +49 -49
- package/skills/vision-engine/SKILL.md +160 -160
- package/skills/vision-engine/agents/openai.yaml +4 -4
- package/skills/vision-engine/references/architecture-and-acceptance.md +194 -194
- package/skills/workspace-conventions/SKILL.md +273 -273
- 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 +209 -209
- 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 +217 -217
- 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,160 +1,160 @@
|
|
|
1
|
-
# v8-security 详细参考 2
|
|
2
|
-
|
|
3
|
-
> 按需读取;本文件由 SKILL.md 的原章节无损拆分。
|
|
4
|
-
|
|
5
|
-
<!-- microi-progressive:chunk id=v8-security-008 sha256=2ff2de57d90237ef31cf6cccdb940b8ebb2a268a7726216946de4ba672a12248 -->
|
|
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=e430777e54dc5c9e24e5f981db467dbe0ed3e9a297042a545891dd644e10a485 -->
|
|
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=26ae8c22e1db1edca4d159d68423ae14ec84b528e5cc4deb305010f89871f57e -->
|
|
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=d625724d1e14db9cbd707b74d5ed1e5cd3fc44d58ff46baed65e3fd09728e817 -->
|
|
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=5f0a43b36ce88e6fed819887acfda86d2b07f5929c958edade902a95b9dfdb66 -->
|
|
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=1cb38480cbab23ca5f76520f1196943db91a7d21601d3aa61324136ca4ab7695 -->
|
|
137
|
-
## 浏览器访问密钥
|
|
138
|
-
|
|
139
|
-
- 站内 `/...` 路由不得交给绝对 URI 解析器当作本机文件 URI;只有完整地址才提取 HTTP 路径。页面范围归一化在 Windows、Linux、macOS 必须一致,保留精确路径与通配符的授权区别。
|
|
140
|
-
|
|
141
|
-
固定看板、电视和信息屏免输入帐号密码时,使用平台 `mci_user_access_key`,禁止自行在接口引擎中保存明文 Secret,也禁止把长期登录 Token 拼进 URL。
|
|
142
|
-
|
|
143
|
-
- 一个帐号可有多个密钥;每个密钥独立名称、到期时间(90天/自定义/永久)、范围、使用审计和吊销状态。永久密钥必须可单独吊销并建议定期人工轮换。
|
|
144
|
-
- 密钥格式固定为 `microi_ak_<48-bit公开前缀>.<128-bit随机秘密>`,当前总长度 41 个字符;只保存完整密钥的 SHA-256 哈希,明文只在创建时返回一次。日志、MongoDB、Redis、异常和回答中不得出现完整密钥。
|
|
145
|
-
- 浏览器启动链接使用 `{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;目标路由必须以 `/` 开头并位于密钥允许页面范围内。
|
|
146
|
-
- 固定电视/看板应保存完整 `/access-login` 链接作为浏览器开机主页或受控书签,不能只保存兑换后的预览页。`access_key` 位于 Hash 中,前端解析后立即 `history.replaceState` 清除;地址栏随后不含密钥是正常安全行为,禁止给目标页重复追加密钥或引入 `permanent=1/keep_login=1` 等客户端寿命参数。永久只描述密钥记录不计划到期;短期受限 Token 正常轮换,会话丢失时重新打开启动链接再次兑换。后端兑换只接受 JSON Body。
|
|
147
|
-
- 兑换得到短期 `_ClientType=AccessKey` Token。JWT 只保存 `MicroiAccessKeyId`,权限范围从共享数据库/Redis实时加载,不能把范围写进共享 `CurrentToken.CurrentUser`。
|
|
148
|
-
- 密钥权限只能收窄:帐号实时角色/菜单/行范围与 `Scopes + AllowedRoutes + AllowedTableNames + AllowedApiEngineKeys + AllowedDataSourceKeys` 取交集。检查必须位于管理员快捷放行之前。
|
|
149
|
-
- 默认只允许 `page:open + form:read`;`form:write/form:export/file:read/api-engine:run/data-source:run` 必须显式启用。`AllowedRoutes` 和 `AllowedTableNames` 可以使用单独值 `*` 表示“全部目标帐号已授权资源”,但检查仍必须位于管理员快捷放行之前并继续执行帐号菜单、表单、部门和行权限;旧 UI 误存的路由值 `/*` 只作为该通配值的兼容别名。`AllowedApiEngineKeys` 和 `AllowedDataSourceKeys` 必须是准确白名单,禁止 `*`。
|
|
150
|
-
- API 放行必须使用按 capability 分类的运行时矩阵,不能靠零散补一个报错路径:页面范围为 `*` 且具有 `page:open` 时才允许 `SysMenu/GetSysMenuStep`;指定页面密钥不得读取完整菜单树。只允许会话启动、页面元数据、表单 CRUD/导出、本人后台任务和本人终端信息等明确运行面;显示密码、密钥管理、菜单/表/字段设计、索引、缓存、服务器、其它终端管理等控制面保持拒绝。
|
|
151
|
-
- 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 的标准列表请求,都不能绕过表名白名单或被误拒绝。
|
|
152
|
-
- FormEngine 的动态友好路由(如 `GetTableData-{table-key}`、`Get-TableData-{table-key}`、`GetFormData-{table-key}` 及写入别名)必须在 API capability 鉴权前归一化。动态路由转换器与访问密钥鉴权必须复用同一个别名解析器,禁止各维护一份前缀清单;归一化只决定所需 scope,URL 后缀还必须与模型绑定后的 `FormEngineKey/TableId/ModuleEngineKey/_SysMenuId` 之一规范化一致,并再次校验准确表或菜单引用。空 Key、前后缀不一致、额外路径段和相似前缀必须拒绝。
|
|
153
|
-
- `ApiEngineController` 的 Run 系列即使标记了 `[AllowAnonymous]`,检测到访问密钥会话后也必须解析实际命中的引擎模型并校验准确 `ApiEngineKey`;数据源运行和后台接口任务同样校验准确 Key。禁止只在 MVC 授权过滤器中检查粗粒度路径,因为匿名兼容入口会跳过该过滤器。
|
|
154
|
-
- 自动登录 URL 必须携带当前 `OsClient`;前端进入 `/access-login` 时先清除 Hash 中的密钥,再用 JSON Body 兑换,并设置有限超时。禁止等待与兑换无关的 SSO 初始化导致无限加载。
|
|
155
|
-
- 管理操作只允许普通登录会话的本人或管理员;访问密钥会话不能创建或吊销密钥。系统账号中的管理入口必须由 `sys_menu.MoreBtns` 动态配置,并通过通用 `V8.OpenDialog` 打开预注册的 `UserAccessKeyPanel`;不得新增业务专用 `V8.OpenUserAccessKeys`,也不得在通用表格/卡片模板中按表名硬编码。按钮显隐不能代替后端逐次鉴权。
|
|
156
|
-
- 多节点共享 Redis 只作为短 TTL 缓存和限流;数据库是事实源,吊销主动清除缓存。不得使用 `static` 字典、本机文件或本地定时器保存密钥状态。
|
|
157
|
-
- 对外仍要求 HTTPS。固定终端使用独立只读帐号,不能用超级管理员帐号创建看板密钥。
|
|
158
|
-
|
|
159
|
-
验收至少覆盖:明文只返回一次、错误密钥固定时间比较、过期/吊销/停用帐号失败、指定页面成功而其它路由失败、全部页面可加载 `GetSysMenuStep`、标准与动态 `GetTableData/GetFormData` 路由均可读取允许表、仅传绑定菜单 Id 的 `ModuleEngineKey` 动态列表成功、动态写路由仍要求 `form:write`、空 Key/前后缀不一致/相似前缀/额外路径段失败、允许表名及对应表 Id/菜单 Id 成功而其它资源失败、FormEngine 设计接口仍拒绝、接口/数据源 Key 精确限制且动态/后台入口不能绕过、普通帐号权限变化即时收窄、两个 API 节点吊销一致生效。
|
|
160
|
-
<!-- /microi-progressive:chunk -->
|
|
1
|
+
# v8-security 详细参考 2
|
|
2
|
+
|
|
3
|
+
> 按需读取;本文件由 SKILL.md 的原章节无损拆分。
|
|
4
|
+
|
|
5
|
+
<!-- microi-progressive:chunk id=v8-security-008 sha256=2ff2de57d90237ef31cf6cccdb940b8ebb2a268a7726216946de4ba672a12248 -->
|
|
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=e430777e54dc5c9e24e5f981db467dbe0ed3e9a297042a545891dd644e10a485 -->
|
|
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=26ae8c22e1db1edca4d159d68423ae14ec84b528e5cc4deb305010f89871f57e -->
|
|
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=d625724d1e14db9cbd707b74d5ed1e5cd3fc44d58ff46baed65e3fd09728e817 -->
|
|
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=5f0a43b36ce88e6fed819887acfda86d2b07f5929c958edade902a95b9dfdb66 -->
|
|
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=1cb38480cbab23ca5f76520f1196943db91a7d21601d3aa61324136ca4ab7695 -->
|
|
137
|
+
## 浏览器访问密钥
|
|
138
|
+
|
|
139
|
+
- 站内 `/...` 路由不得交给绝对 URI 解析器当作本机文件 URI;只有完整地址才提取 HTTP 路径。页面范围归一化在 Windows、Linux、macOS 必须一致,保留精确路径与通配符的授权区别。
|
|
140
|
+
|
|
141
|
+
固定看板、电视和信息屏免输入帐号密码时,使用平台 `mci_user_access_key`,禁止自行在接口引擎中保存明文 Secret,也禁止把长期登录 Token 拼进 URL。
|
|
142
|
+
|
|
143
|
+
- 一个帐号可有多个密钥;每个密钥独立名称、到期时间(90天/自定义/永久)、范围、使用审计和吊销状态。永久密钥必须可单独吊销并建议定期人工轮换。
|
|
144
|
+
- 密钥格式固定为 `microi_ak_<48-bit公开前缀>.<128-bit随机秘密>`,当前总长度 41 个字符;只保存完整密钥的 SHA-256 哈希,明文只在创建时返回一次。日志、MongoDB、Redis、异常和回答中不得出现完整密钥。
|
|
145
|
+
- 浏览器启动链接使用 `{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;目标路由必须以 `/` 开头并位于密钥允许页面范围内。
|
|
146
|
+
- 固定电视/看板应保存完整 `/access-login` 链接作为浏览器开机主页或受控书签,不能只保存兑换后的预览页。`access_key` 位于 Hash 中,前端解析后立即 `history.replaceState` 清除;地址栏随后不含密钥是正常安全行为,禁止给目标页重复追加密钥或引入 `permanent=1/keep_login=1` 等客户端寿命参数。永久只描述密钥记录不计划到期;短期受限 Token 正常轮换,会话丢失时重新打开启动链接再次兑换。后端兑换只接受 JSON Body。
|
|
147
|
+
- 兑换得到短期 `_ClientType=AccessKey` Token。JWT 只保存 `MicroiAccessKeyId`,权限范围从共享数据库/Redis实时加载,不能把范围写进共享 `CurrentToken.CurrentUser`。
|
|
148
|
+
- 密钥权限只能收窄:帐号实时角色/菜单/行范围与 `Scopes + AllowedRoutes + AllowedTableNames + AllowedApiEngineKeys + AllowedDataSourceKeys` 取交集。检查必须位于管理员快捷放行之前。
|
|
149
|
+
- 默认只允许 `page:open + form:read`;`form:write/form:export/file:read/api-engine:run/data-source:run` 必须显式启用。`AllowedRoutes` 和 `AllowedTableNames` 可以使用单独值 `*` 表示“全部目标帐号已授权资源”,但检查仍必须位于管理员快捷放行之前并继续执行帐号菜单、表单、部门和行权限;旧 UI 误存的路由值 `/*` 只作为该通配值的兼容别名。`AllowedApiEngineKeys` 和 `AllowedDataSourceKeys` 必须是准确白名单,禁止 `*`。
|
|
150
|
+
- API 放行必须使用按 capability 分类的运行时矩阵,不能靠零散补一个报错路径:页面范围为 `*` 且具有 `page:open` 时才允许 `SysMenu/GetSysMenuStep`;指定页面密钥不得读取完整菜单树。只允许会话启动、页面元数据、表单 CRUD/导出、本人后台任务和本人终端信息等明确运行面;显示密码、密钥管理、菜单/表/字段设计、索引、缓存、服务器、其它终端管理等控制面保持拒绝。
|
|
151
|
+
- 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 的标准列表请求,都不能绕过表名白名单或被误拒绝。
|
|
152
|
+
- FormEngine 的动态友好路由(如 `GetTableData-{table-key}`、`Get-TableData-{table-key}`、`GetFormData-{table-key}` 及写入别名)必须在 API capability 鉴权前归一化。动态路由转换器与访问密钥鉴权必须复用同一个别名解析器,禁止各维护一份前缀清单;归一化只决定所需 scope,URL 后缀还必须与模型绑定后的 `FormEngineKey/TableId/ModuleEngineKey/_SysMenuId` 之一规范化一致,并再次校验准确表或菜单引用。空 Key、前后缀不一致、额外路径段和相似前缀必须拒绝。
|
|
153
|
+
- `ApiEngineController` 的 Run 系列即使标记了 `[AllowAnonymous]`,检测到访问密钥会话后也必须解析实际命中的引擎模型并校验准确 `ApiEngineKey`;数据源运行和后台接口任务同样校验准确 Key。禁止只在 MVC 授权过滤器中检查粗粒度路径,因为匿名兼容入口会跳过该过滤器。
|
|
154
|
+
- 自动登录 URL 必须携带当前 `OsClient`;前端进入 `/access-login` 时先清除 Hash 中的密钥,再用 JSON Body 兑换,并设置有限超时。禁止等待与兑换无关的 SSO 初始化导致无限加载。
|
|
155
|
+
- 管理操作只允许普通登录会话的本人或管理员;访问密钥会话不能创建或吊销密钥。系统账号中的管理入口必须由 `sys_menu.MoreBtns` 动态配置,并通过通用 `V8.OpenDialog` 打开预注册的 `UserAccessKeyPanel`;不得新增业务专用 `V8.OpenUserAccessKeys`,也不得在通用表格/卡片模板中按表名硬编码。按钮显隐不能代替后端逐次鉴权。
|
|
156
|
+
- 多节点共享 Redis 只作为短 TTL 缓存和限流;数据库是事实源,吊销主动清除缓存。不得使用 `static` 字典、本机文件或本地定时器保存密钥状态。
|
|
157
|
+
- 对外仍要求 HTTPS。固定终端使用独立只读帐号,不能用超级管理员帐号创建看板密钥。
|
|
158
|
+
|
|
159
|
+
验收至少覆盖:明文只返回一次、错误密钥固定时间比较、过期/吊销/停用帐号失败、指定页面成功而其它路由失败、全部页面可加载 `GetSysMenuStep`、标准与动态 `GetTableData/GetFormData` 路由均可读取允许表、仅传绑定菜单 Id 的 `ModuleEngineKey` 动态列表成功、动态写路由仍要求 `form:write`、空 Key/前后缀不一致/相似前缀/额外路径段失败、允许表名及对应表 Id/菜单 Id 成功而其它资源失败、FormEngine 设计接口仍拒绝、接口/数据源 Key 精确限制且动态/后台入口不能绕过、普通帐号权限变化即时收窄、两个 API 节点吊销一致生效。
|
|
160
|
+
<!-- /microi-progressive:chunk -->
|